Merge remote-tracking branch 'upstream/develop' into develop

* upstream/develop: (252 commits)
  chore: update browsers list
  fix testomatio
  Ignore .cache path in jest
  Upgrade Cypress
  fix: use db for parser.yy
  Fix for padding issue and some cleanup
  Updated release version to 9.1.2
  Test file
  Added placeholder docs fro C4C diagram
  chore(deps-dev): bump webpack-cli from 4.9.2 to 4.10.0 (#3130)
  chore(deps-dev): bump cypress from 9.7.0 to 10.1.0
  chore(deps-dev): bump lint-staged from 13.0.0 to 13.0.1 (#3132)
  chore(deps-dev): bump @applitools/eyes-cypress from 3.26.1 to 3.26.2 (#3136)
  chore(deps-dev): bump webpack-dev-server from 4.9.1 to 4.9.2 (#3133)
  chore(deps-dev): bump babel-jest from 28.1.0 to 28.1.1 (#3137)
  chore(deps-dev): bump jest-environment-jsdom from 28.1.0 to 28.1.1 (#3129)
  chore(deps-dev): bump @babel/core from 7.18.2 to 7.18.5 (#3134)
  chore(deps-dev): bump jest from 28.1.0 to 28.1.1 (#3131)
  chore: update browsers list
  typos in configuration.md corrected
  ...
This commit is contained in:
Sidharth Vinod
2022-06-20 13:01:58 +05:30
214 changed files with 11597 additions and 167476 deletions

View File

@@ -1,2 +1,3 @@
dist/**
.github/**
docs/Setup.md

View File

@@ -13,17 +13,25 @@
},
"sourceType": "module"
},
"extends": ["eslint:recommended", "plugin:jsdoc/recommended", "plugin:markdown/recommended", "plugin:prettier/recommended"],
"plugins": ["html", "jest", "jsdoc", "prettier"],
"extends": [
"eslint:recommended",
//"plugin:jsdoc/recommended",
"plugin:json/recommended",
// "plugin:markdown/recommended",
"plugin:prettier/recommended"
],
"plugins": ["html", "jest", "jsdoc", "json", "prettier"],
"rules": {
"no-prototype-builtins": 0,
"no-unused-vars": 0,
"jsdoc/check-indentation": 0,
"jsdoc/check-alignment": 0,
"jsdoc/check-line-alignment": 0,
"jsdoc/multiline-blocks": 0,
"jsdoc/newline-after-description": 0,
"jsdoc/tag-lines": 0,
"no-prototype-builtins": "off",
"no-unused-vars": "off",
"jsdoc/check-indentation": "off",
"jsdoc/check-alignment": "off",
"jsdoc/check-line-alignment": "off",
"jsdoc/multiline-blocks": "off",
"jsdoc/newline-after-description": "off",
"jsdoc/tag-lines": "off",
"cypress/no-async-tests": "off",
"json/*": ["error", "allowComments"],
"no-empty": ["error", { "allowEmptyCatch": true }]
},
"overrides": [
@@ -33,6 +41,12 @@
"no-undef": "off",
"jsdoc/require-jsdoc": "off"
}
},
{
"files": "./**/*.md/*.html",
"rules": {
"prettier/prettier": "off"
}
}
]
}

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
* text=auto

4
.github/codeql/codeql-config.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
name: "CodeQL config"
paths-ignore:
- dist
- cypress

View File

@@ -1,6 +1,15 @@
name: Build
on: [push, pull_request]
on:
push: {}
pull_request:
types:
- opened
- synchronize
- ready_for_review
permissions:
contents: read
jobs:
build:
@@ -30,29 +39,7 @@ jobs:
run: yarn build
- name: Upload Build as Artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: dist
path: dist
- name: Run Unit Tests
run: |
yarn test --coverage
#- name: Upload Test Results
# uses: coverallsapp/github-action@v1.0.1
# with:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# parallel: true
# - name: Run E2E Tests
# run: yarn e2e
# env:
# PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
# CYPRESS_CACHE_FOLDER: .cache/Cypress
#- name: Post Upload Test Results
# uses: coverallsapp/github-action@master
# with:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# parallel-finished: true

View File

@@ -10,6 +10,9 @@ on:
branches:
- gh-pages
permissions:
contents: read
jobs:
check:
runs-on: ubuntu-latest

View File

@@ -1,4 +1,10 @@
on: [push]
on:
push: {}
pull_request:
types:
- opened
- synchronize
- ready_for_review
name: Static analysis
@@ -13,7 +19,6 @@ jobs:
- uses: testomatio/check-tests@stable
with:
framework: cypress
tests: "./cypress/integration/**/**.spec.js"
tests: "./cypress/e2e/**/**.spec.js"
token: ${{ secrets.GITHUB_TOKEN }}
has-tests-label: true

63
.github/workflows/codeql.yml vendored Normal file
View File

@@ -0,0 +1,63 @@
name: "CodeQL"
on:
push:
branches: [ develop ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ develop ]
types:
- opened
- synchronize
- ready_for_review
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
config-file: ./.github/codeql/codeql-config.yml
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

20
.github/workflows/dependency-review.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
# Dependency Review Action
#
# This Action will scan dependency manifest files that change as part of a Pull Reqest, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging.
#
# Source repository: https://github.com/actions/dependency-review-action
# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
name: 'Dependency Review'
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v3
- name: 'Dependency Review'
uses: actions/dependency-review-action@v1

View File

@@ -2,6 +2,9 @@ name: E2E
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
@@ -29,24 +32,7 @@ jobs:
- name: Run Build
run: yarn build
# - name: Run e2e Tests
# run: |
# yarn e2e
#- name: Upload Test Results
# uses: coverallsapp/github-action@v1.0.1
# with:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# parallel: true
- name: Run E2E Tests
run: yarn e2e
env:
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
CYPRESS_CACHE_FOLDER: .cache/Cypress
#- name: Post Upload Test Results
# uses: coverallsapp/github-action@master
# with:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# parallel-finished: true

39
.github/workflows/lint.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: Lint
on:
push: {}
pull_request:
types:
- opened
- synchronize
- ready_for_review
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
steps:
- uses: actions/checkout@v3
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
cache: yarn
node-version: ${{ matrix.node-version }}
- name: Install Yarn
run: npm i yarn --global
- name: Install Packages
run: |
yarn install --frozen-lockfile
env:
CYPRESS_CACHE_FOLDER: .cache/Cypress
- name: Run Linting
run: yarn lint

View File

@@ -1,5 +1,11 @@
name: Validate PR Labeler Configuration
on: [push, pull_request]
on:
push: {}
pull_request:
types:
- opened
- synchronize
- ready_for_review
jobs:
pr-labeler:

34
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: Unit Tests
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
steps:
- uses: actions/checkout@v3
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
cache: yarn
node-version: ${{ matrix.node-version }}
- name: Install Yarn
run: npm i yarn --global
- name: Install Packages
run: |
yarn install --frozen-lockfile
env:
CYPRESS_CACHE_FOLDER: .cache/Cypress
- name: Run Unit Tests
run: |
yarn ci --coverage

0
.husky/commit-msg Normal file → Executable file
View File

0
.husky/pre-commit Normal file → Executable file
View File

View File

@@ -1,5 +1,5 @@
{
"*.{js,html,md}": [
"*.{js,json,html,md}": [
"yarn lint:fix"
]
}

View File

@@ -3,12 +3,9 @@
"libs": [
"browser"
],
"loadEagerly": [
"path/to/your/js/**/*.js"
],
"loadEagerly": [],
"dontLoad": [
"node_modules/**",
"path/to/your/js/**/*.js"
"node_modules/**"
],
"plugins": {
"modules": {},

View File

@@ -23,7 +23,7 @@
- Missing fontawesome icon support [\#830](https://github.com/knsv/mermaid/issues/830)
- Docs for integration with wiki.js? [\#829](https://github.com/knsv/mermaid/issues/829)
- Is this project still maintained? [\#826](https://github.com/knsv/mermaid/issues/826)
- typroa [\#823](https://github.com/knsv/mermaid/issues/823)
- typora [\#823](https://github.com/knsv/mermaid/issues/823)
- Maintain the order of the nodes in Flowchart [\#815](https://github.com/knsv/mermaid/issues/815)
- Overlap, Overflow and cut titles in flowchart [\#814](https://github.com/knsv/mermaid/issues/814)
- How load mermaidApi notejs electron [\#813](https://github.com/knsv/mermaid/issues/813)

View File

@@ -2,7 +2,7 @@
So you want to help? That's great!
![Image of happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif)
![Happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif)
Here are a few things to know to get you started on the right path.
@@ -76,7 +76,7 @@ This is important so that, if someone else does a change to the grammar that doe
### **Add e2e tests**
This tests the rendering and visual apearance of the diagram. This ensures that the rendering of that feature in the e2e will be reviewed in the release process going forward. Less chance that it breaks!
This tests the rendering and visual appearance of the diagram. This ensures that the rendering of that feature in the e2e will be reviewed in the release process going forward. Less chance that it breaks!
To start working with the e2e tests, run `yarn dev` to start the dev server, after that start cypress by running `cypress open` in the mermaid folder. (Make sure you have path to cypress in order, the binary is located in node_modules/.bin).
@@ -114,7 +114,7 @@ Finally, if it is not in the documentation, no one will know about it and then *
The docs are located in the docs folder and are ofc written in markdown. Just pick the right section and start typing. If you want to add to the structure as in adding a new section and new file you do that via the _navbar.md.
The changes in master is reflected in http://mermaid-js.github.io/mermaid/ once released the updates are committed to https://mermaid-js.github.io/#/
The changes in master is reflected in https://mermaid-js.github.io/mermaid/ once released the updates are committed to https://mermaid-js.github.io/#/
## Last words
@@ -123,4 +123,4 @@ Don't get daunted if it is hard in the beginning. We have a great community with
[Join our slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
![Image of superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif)
![A superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif)

View File

@@ -2,13 +2,15 @@
English | [简体中文](./README.zh-CN.md)
![banner](./img/header.png)
<img src="./img/header.png" alt="" />
:trophy: **Mermaid was nominated and won the [JS Open Source Awards (2019)](https://osawards.com/javascript/2019) in the category "The most exciting use of technology"!!!**
**Thanks to all involved, people committing pull requests, people answering questions! 🙏**
<a href="https://mermaid-js.github.io/mermaid/landing/" alt="Link to landing page for the book The Official Guide To mermaid.js"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/img/book-banner-post-release.jpg"></a>
<a href="https://mermaid-js.github.io/mermaid/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
## About
@@ -21,14 +23,27 @@ Diagramming and documentation costs precious developer time and gets outdated qu
But not having diagrams or docs ruins productivity and hurts organizational learning.<br/>
Mermaid addresses this problem by enabling users to create easily modifiable diagrams, it can also be made part of production scripts (and other pieces of code).<br/>
<br/>
Mermaid allows even non-programmers to easily create detailed and diagrams through the [Mermaid Live Editor](https://mermaid-js.github.io/mermaid-live-editor/).<br/>
Mermaid allows even non-programmers to easily create detailed diagrams through the [Mermaid Live Editor](https://mermaid-js.github.io/mermaid-live-editor/).<br/>
[Tutorials](./docs/Tutorials.md) has video tutorials.
Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/integrations.md).
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/n00b-overview.md) and [Usage](./docs/usage.md).
You can also use Mermaid within [GitHub](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) as well many of your other favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/integrations.md).
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/n00b-overview.md), [Usage](./docs/usage.md) and [Tutorials](./docs/Tutorials.md).
🌐 [CDN](https://unpkg.com/mermaid/) | 📖 [Documentation](https://mermaidjs.github.io) | 🙌 [Contribution](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md) | 📜 [Changelog](./docs/CHANGELOG.md)
In our release process we rely heavily on visual regression tests using [applitools](https://applitools.com/). Applitools is a great service which has been easy to use and integrate with our tests.
<a href="https://applitools.com/">
<svg width="170" height="32" viewBox="0 0 170 32" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="a" maskUnits="userSpaceOnUse" x="27" y="0" width="143" height="32"><path fill-rule="evenodd" clip-rule="evenodd" d="M27.732.227h141.391v31.19H27.733V.227z" fill="#fff"></path></mask><g mask="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M153.851 22.562l1.971-3.298c1.291 1.219 3.837 2.402 5.988 2.402 1.971 0 2.903-.753 2.903-1.829 0-2.832-10.253-.502-10.253-7.313 0-2.904 2.51-5.45 7.099-5.45 2.904 0 5.234 1.004 6.955 2.367l-1.829 3.226c-1.039-1.075-3.011-2.008-5.126-2.008-1.65 0-2.725.717-2.725 1.685 0 2.546 10.289.395 10.289 7.386 0 3.19-2.724 5.52-7.528 5.52-3.012 0-5.916-1.003-7.744-2.688zm-5.7 2.259h4.553V.908h-4.553v23.913zm-6.273-8.676c0-2.689-1.578-5.02-4.446-5.02-2.832 0-4.409 2.331-4.409 5.02 0 2.724 1.577 5.055 4.409 5.055 2.868 0 4.446-2.33 4.446-5.055zm-13.588 0c0-4.912 3.442-9.07 9.142-9.07 5.736 0 9.178 4.158 9.178 9.07 0 4.911-3.442 9.106-9.178 9.106-5.7 0-9.142-4.195-9.142-9.106zm-5.628 0c0-2.689-1.577-5.02-4.445-5.02-2.832 0-4.41 2.331-4.41 5.02 0 2.724 1.578 5.055 4.41 5.055 2.868 0 4.445-2.33 4.445-5.055zm-13.587 0c0-4.912 3.441-9.07 9.142-9.07 5.736 0 9.178 4.158 9.178 9.07 0 4.911-3.442 9.106-9.178 9.106-5.701 0-9.142-4.195-9.142-9.106zm-8.425 4.338v-8.999h-2.868v-3.98h2.868V2.773h4.553v4.733h3.514v3.979h-3.514v7.78c0 1.111.574 1.936 1.578 1.936.681 0 1.326-.251 1.577-.538l.968 3.478c-.681.609-1.9 1.11-3.8 1.11-3.191 0-4.876-1.648-4.876-4.767zm-8.962 4.338h4.553V7.505h-4.553V24.82zm-.43-21.905a2.685 2.685 0 012.688-2.69c1.506 0 2.725 1.184 2.725 2.69a2.724 2.724 0 01-2.725 2.724c-1.47 0-2.688-1.219-2.688-2.724zM84.482 24.82h4.553V.908h-4.553v23.913zm-6.165-8.676c0-2.976-1.793-5.02-4.41-5.02-1.47 0-3.119.825-3.908 1.973v6.094c.753 1.111 2.438 2.008 3.908 2.008 2.617 0 4.41-2.044 4.41-5.055zm-8.318 6.453v8.82h-4.553V7.504H70v2.187c1.327-1.685 3.227-2.618 5.342-2.618 4.446 0 7.672 3.299 7.672 9.07 0 5.773-3.226 9.107-7.672 9.107-2.043 0-3.907-.86-5.342-2.653zm-10.718-6.453c0-2.976-1.793-5.02-4.41-5.02-1.47 0-3.119.825-3.908 1.973v6.094c.753 1.111 2.438 2.008 3.908 2.008 2.617 0 4.41-2.044 4.41-5.055zm-8.318 6.453v8.82H46.41V7.504h4.553v2.187c1.327-1.685 3.227-2.618 5.342-2.618 4.446 0 7.672 3.299 7.672 9.07 0 5.773-3.226 9.107-7.672 9.107-2.043 0-3.908-.86-5.342-2.653zm-11.758-1.936V18.51c-.753-1.004-2.187-1.542-3.657-1.542-1.793 0-3.263.968-3.263 2.617 0 1.65 1.47 2.582 3.263 2.582 1.47 0 2.904-.502 3.657-1.506zm0 4.159v-1.829c-1.183 1.434-3.227 2.259-5.485 2.259-2.761 0-5.988-1.864-5.988-5.736 0-4.087 3.227-5.593 5.988-5.593 2.33 0 4.337.753 5.485 2.115V13.85c0-1.756-1.506-2.904-3.8-2.904-1.829 0-3.55.717-4.984 2.044L28.63 9.8c2.115-1.901 4.84-2.726 7.564-2.726 3.98 0 7.6 1.578 7.6 6.561v11.186h-4.588z" fill="#00A298"></path></g><path fill-rule="evenodd" clip-rule="evenodd" d="M14.934 16.177c0 1.287-.136 2.541-.391 3.752-1.666-1.039-3.87-2.288-6.777-3.752 2.907-1.465 5.11-2.714 6.777-3.753.255 1.211.39 2.466.39 3.753m4.6-7.666V4.486a78.064 78.064 0 01-4.336 3.567c-1.551-2.367-3.533-4.038-6.14-5.207C11.1 4.658 12.504 6.7 13.564 9.262 5.35 15.155 0 16.177 0 16.177s5.35 1.021 13.564 6.915c-1.06 2.563-2.463 4.603-4.507 6.415 2.607-1.169 4.589-2.84 6.14-5.207a77.978 77.978 0 014.336 3.568v-4.025s-.492-.82-2.846-2.492c.6-1.611.93-3.354.93-5.174a14.8 14.8 0 00-.93-5.174c2.354-1.673 2.846-2.492 2.846-2.492" fill="#00A298"></path></svg>
</a>
<!-- </Main description> -->
## Examples
@@ -36,10 +51,11 @@ For a more detailed introduction to Mermaid and some of its more basic uses, loo
__The following are some examples of the diagrams, charts and graphs that can be made using Mermaid. Click here jump into the [text syntax](https://mermaid-js.github.io/mermaid/#/n00b-syntaxReference).__
<!-- <Flowchart> -->
## Flowchart [<a href="https://mermaid-js.github.io/mermaid/#/flowchart">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBW0hhcmRdIC0tPnxUZXh0fCBCKFJvdW5kKVxuICAgIEIgLS0-IEN7RGVjaXNpb259XG4gICAgQyAtLT58T25lfCBEW1Jlc3VsdCAxXVxuICAgIEMgLS0-fFR3b3wgRVtSZXN1bHQgMl0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
### Flowchart [<a href="https://mermaid-js.github.io/mermaid/#/flowchart">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBW0hhcmRdIC0tPnxUZXh0fCBCKFJvdW5kKVxuICAgIEIgLS0-IEN7RGVjaXNpb259XG4gICAgQyAtLT58T25lfCBEW1Jlc3VsdCAxXVxuICAgIEMgLS0-fFR3b3wgRVtSZXN1bHQgMl0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
```
flowchart LR
A[Hard] -->|Text| B(Round)
B --> C{Decision}
C -->|One| D[Result 1]
@@ -47,6 +63,7 @@ C -->|Two| E[Result 2]
```
```mermaid
flowchart LR
A[Hard] -->|Text| B(Round)
B --> C{Decision}
C -->|One| D[Result 1]
@@ -54,7 +71,7 @@ C -->|Two| E[Result 2]
```
## Sequence diagram [<a href="https://mermaid-js.github.io/mermaid/#/sequenceDiagram">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic2VxdWVuY2VEaWFncmFtXG5BbGljZS0-PkpvaG46IEhlbGxvIEpvaG4sIGhvdyBhcmUgeW91P1xubG9vcCBIZWFsdGhjaGVja1xuICAgIEpvaG4tPj5Kb2huOiBGaWdodCBhZ2FpbnN0IGh5cG9jaG9uZHJpYVxuZW5kXG5Ob3RlIHJpZ2h0IG9mIEpvaG46IFJhdGlvbmFsIHRob3VnaHRzIVxuSm9obi0tPj5BbGljZTogR3JlYXQhXG5Kb2huLT4-Qm9iOiBIb3cgYWJvdXQgeW91P1xuQm9iLS0-PkpvaG46IEpvbGx5IGdvb2QhIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
### Sequence diagram [<a href="https://mermaid-js.github.io/mermaid/#/sequenceDiagram">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic2VxdWVuY2VEaWFncmFtXG5BbGljZS0-PkpvaG46IEhlbGxvIEpvaG4sIGhvdyBhcmUgeW91P1xubG9vcCBIZWFsdGhjaGVja1xuICAgIEpvaG4tPj5Kb2huOiBGaWdodCBhZ2FpbnN0IGh5cG9jaG9uZHJpYVxuZW5kXG5Ob3RlIHJpZ2h0IG9mIEpvaG46IFJhdGlvbmFsIHRob3VnaHRzIVxuSm9obi0tPj5BbGljZTogR3JlYXQhXG5Kb2huLT4-Qm9iOiBIb3cgYWJvdXQgeW91P1xuQm9iLS0-PkpvaG46IEpvbGx5IGdvb2QhIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
```
sequenceDiagram
@@ -79,7 +96,7 @@ John->>Bob: How about you?
Bob-->>John: Jolly good!
```
## Gantt chart [<a href="https://mermaid-js.github.io/mermaid/#/gantt">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2FudHRcbnNlY3Rpb24gU2VjdGlvblxuQ29tcGxldGVkIDpkb25lLCAgICBkZXMxLCAyMDE0LTAxLTA2LDIwMTQtMDEtMDhcbkFjdGl2ZSAgICAgICAgOmFjdGl2ZSwgIGRlczIsIDIwMTQtMDEtMDcsIDNkXG5QYXJhbGxlbCAxICAgOiAgICAgICAgIGRlczMsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAyICAgOiAgICAgICAgIGRlczQsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAzICAgOiAgICAgICAgIGRlczUsIGFmdGVyIGRlczMsIDFkXG5QYXJhbGxlbCA0ICAgOiAgICAgICAgIGRlczYsIGFmdGVyIGRlczQsIDFkIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
### Gantt chart [<a href="https://mermaid-js.github.io/mermaid/#/gantt">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2FudHRcbnNlY3Rpb24gU2VjdGlvblxuQ29tcGxldGVkIDpkb25lLCAgICBkZXMxLCAyMDE0LTAxLTA2LDIwMTQtMDEtMDhcbkFjdGl2ZSAgICAgICAgOmFjdGl2ZSwgIGRlczIsIDIwMTQtMDEtMDcsIDNkXG5QYXJhbGxlbCAxICAgOiAgICAgICAgIGRlczMsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAyICAgOiAgICAgICAgIGRlczQsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAzICAgOiAgICAgICAgIGRlczUsIGFmdGVyIGRlczMsIDFkXG5QYXJhbGxlbCA0ICAgOiAgICAgICAgIGRlczYsIGFmdGVyIGRlczQsIDFkIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
```
gantt
@@ -102,7 +119,7 @@ gantt
Parallel 4 : des6, after des4, 1d
```
## Class diagram [<a href="https://mermaid-js.github.io/mermaid/#/classDiagram">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiY2xhc3NEaWFncmFtXG5DbGFzczAxIDx8LS0gQXZlcnlMb25nQ2xhc3MgOiBDb29sXG48PGludGVyZmFjZT4-IENsYXNzMDFcbkNsYXNzMDkgLS0-IEMyIDogV2hlcmUgYW0gaT9cbkNsYXNzMDkgLS0qIEMzXG5DbGFzczA5IC0tfD4gQ2xhc3MwN1xuQ2xhc3MwNyA6IGVxdWFscygpXG5DbGFzczA3IDogT2JqZWN0W10gZWxlbWVudERhdGFcbkNsYXNzMDEgOiBzaXplKClcbkNsYXNzMDEgOiBpbnQgY2hpbXBcbkNsYXNzMDEgOiBpbnQgZ29yaWxsYVxuY2xhc3MgQ2xhc3MxMCB7XG4gID4-c2VydmljZT4-XG4gIGludCBpZFxuICBzaXplKClcbn0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
### Class diagram [<a href="https://mermaid-js.github.io/mermaid/#/classDiagram">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiY2xhc3NEaWFncmFtXG5DbGFzczAxIDx8LS0gQXZlcnlMb25nQ2xhc3MgOiBDb29sXG48PGludGVyZmFjZT4-IENsYXNzMDFcbkNsYXNzMDkgLS0-IEMyIDogV2hlcmUgYW0gaT9cbkNsYXNzMDkgLS0qIEMzXG5DbGFzczA5IC0tfD4gQ2xhc3MwN1xuQ2xhc3MwNyA6IGVxdWFscygpXG5DbGFzczA3IDogT2JqZWN0W10gZWxlbWVudERhdGFcbkNsYXNzMDEgOiBzaXplKClcbkNsYXNzMDEgOiBpbnQgY2hpbXBcbkNsYXNzMDEgOiBpbnQgZ29yaWxsYVxuY2xhc3MgQ2xhc3MxMCB7XG4gID4-c2VydmljZT4-XG4gIGludCBpZFxuICBzaXplKClcbn0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
```
classDiagram
@@ -141,7 +158,7 @@ class Class10 {
}
```
## State diagram [<a href="https://mermaid-js.github.io/mermaid/#/stateDiagram">docs</a> - <a href="https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtLXYyXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQiLCJ0aGVtZVZhcmlhYmxlcyI6eyJiYWNrZ3JvdW5kIjoid2hpdGUiLCJwcmltYXJ5Q29sb3IiOiIjRUNFQ0ZGIiwic2Vjb25kYXJ5Q29sb3IiOiIjZmZmZmRlIiwidGVydGlhcnlDb2xvciI6ImhzbCg4MCwgMTAwJSwgOTYuMjc0NTA5ODAzOSUpIiwicHJpbWFyeUJvcmRlckNvbG9yIjoiaHNsKDI0MCwgNjAlLCA4Ni4yNzQ1MDk4MDM5JSkiLCJzZWNvbmRhcnlCb3JkZXJDb2xvciI6ImhzbCg2MCwgNjAlLCA4My41Mjk0MTE3NjQ3JSkiLCJ0ZXJ0aWFyeUJvcmRlckNvbG9yIjoiaHNsKDgwLCA2MCUsIDg2LjI3NDUwOTgwMzklKSIsInByaW1hcnlUZXh0Q29sb3IiOiIjMTMxMzAwIiwic2Vjb25kYXJ5VGV4dENvbG9yIjoiIzAwMDAyMSIsInRlcnRpYXJ5VGV4dENvbG9yIjoicmdiKDkuNTAwMDAwMDAwMSwgOS41MDAwMDAwMDAxLCA5LjUwMDAwMDAwMDEpIiwibGluZUNvbG9yIjoiIzMzMzMzMyIsInRleHRDb2xvciI6IiMzMzMiLCJtYWluQmtnIjoiI0VDRUNGRiIsInNlY29uZEJrZyI6IiNmZmZmZGUiLCJib3JkZXIxIjoiIzkzNzBEQiIsImJvcmRlcjIiOiIjYWFhYTMzIiwiYXJyb3doZWFkQ29sb3IiOiIjMzMzMzMzIiwiZm9udEZhbWlseSI6IlwidHJlYnVjaGV0IG1zXCIsIHZlcmRhbmEsIGFyaWFsIiwiZm9udFNpemUiOiIxNnB4IiwibGFiZWxCYWNrZ3JvdW5kIjoiI2U4ZThlOCIsIm5vZGVCa2ciOiIjRUNFQ0ZGIiwibm9kZUJvcmRlciI6IiM5MzcwREIiLCJjbHVzdGVyQmtnIjoiI2ZmZmZkZSIsImNsdXN0ZXJCb3JkZXIiOiIjYWFhYTMzIiwiZGVmYXVsdExpbmtDb2xvciI6IiMzMzMzMzMiLCJ0aXRsZUNvbG9yIjoiIzMzMyIsImVkZ2VMYWJlbEJhY2tncm91bmQiOiIjZThlOGU4IiwiYWN0b3JCb3JkZXIiOiJoc2woMjU5LjYyNjE2ODIyNDMsIDU5Ljc3NjUzNjMxMjglLCA4Ny45MDE5NjA3ODQzJSkiLCJhY3RvckJrZyI6IiNFQ0VDRkYiLCJhY3RvclRleHRDb2xvciI6ImJsYWNrIiwiYWN0b3JMaW5lQ29sb3IiOiJncmV5Iiwic2lnbmFsQ29sb3IiOiIjMzMzIiwic2lnbmFsVGV4dENvbG9yIjoiIzMzMyIsImxhYmVsQm94QmtnQ29sb3IiOiIjRUNFQ0ZGIiwibGFiZWxCb3hCb3JkZXJDb2xvciI6ImhzbCgyNTkuNjI2MTY4MjI0MywgNTkuNzc2NTM2MzEyOCUsIDg3LjkwMTk2MDc4NDMlKSIsImxhYmVsVGV4dENvbG9yIjoiYmxhY2siLCJsb29wVGV4dENvbG9yIjoiYmxhY2siLCJub3RlQm9yZGVyQ29sb3IiOiIjYWFhYTMzIiwibm90ZUJrZ0NvbG9yIjoiI2ZmZjVhZCIsIm5vdGVUZXh0Q29sb3IiOiJibGFjayIsImFjdGl2YXRpb25Cb3JkZXJDb2xvciI6IiM2NjYiLCJhY3RpdmF0aW9uQmtnQ29sb3IiOiIjZjRmNGY0Iiwic2VxdWVuY2VOdW1iZXJDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yIjoicmdiYSgxMDIsIDEwMiwgMjU1LCAwLjQ5KSIsImFsdFNlY3Rpb25Ca2dDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yMiI6IiNmZmY0MDAiLCJ0YXNrQm9yZGVyQ29sb3IiOiIjNTM0ZmJjIiwidGFza0JrZ0NvbG9yIjoiIzhhOTBkZCIsInRhc2tUZXh0TGlnaHRDb2xvciI6IndoaXRlIiwidGFza1RleHRDb2xvciI6IndoaXRlIiwidGFza1RleHREYXJrQ29sb3IiOiJibGFjayIsInRhc2tUZXh0T3V0c2lkZUNvbG9yIjoiYmxhY2siLCJ0YXNrVGV4dENsaWNrYWJsZUNvbG9yIjoiIzAwMzE2MyIsImFjdGl2ZVRhc2tCb3JkZXJDb2xvciI6IiM1MzRmYmMiLCJhY3RpdmVUYXNrQmtnQ29sb3IiOiIjYmZjN2ZmIiwiZ3JpZENvbG9yIjoibGlnaHRncmV5IiwiZG9uZVRhc2tCa2dDb2xvciI6ImxpZ2h0Z3JleSIsImRvbmVUYXNrQm9yZGVyQ29sb3IiOiJncmV5IiwiY3JpdEJvcmRlckNvbG9yIjoiI2ZmODg4OCIsImNyaXRCa2dDb2xvciI6InJlZCIsInRvZGF5TGluZUNvbG9yIjoicmVkIiwibGFiZWxDb2xvciI6ImJsYWNrIiwiZXJyb3JCa2dDb2xvciI6IiM1NTIyMjIiLCJlcnJvclRleHRDb2xvciI6IiM1NTIyMjIiLCJjbGFzc1RleHQiOiIjMTMxMzAwIiwiZmlsbFR5cGUwIjoiI0VDRUNGRiIsImZpbGxUeXBlMSI6IiNmZmZmZGUiLCJmaWxsVHlwZTIiOiJoc2woMzA0LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTMiOiJoc2woMTI0LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkiLCJmaWxsVHlwZTQiOiJoc2woMTc2LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTUiOiJoc2woLTQsIDEwMCUsIDkzLjUyOTQxMTc2NDclKSIsImZpbGxUeXBlNiI6ImhzbCg4LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTciOiJoc2woMTg4LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkifX0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9">live editor</a>]
### State diagram [<a href="https://mermaid-js.github.io/mermaid/#/stateDiagram">docs</a> - <a href="https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtLXYyXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQiLCJ0aGVtZVZhcmlhYmxlcyI6eyJiYWNrZ3JvdW5kIjoid2hpdGUiLCJwcmltYXJ5Q29sb3IiOiIjRUNFQ0ZGIiwic2Vjb25kYXJ5Q29sb3IiOiIjZmZmZmRlIiwidGVydGlhcnlDb2xvciI6ImhzbCg4MCwgMTAwJSwgOTYuMjc0NTA5ODAzOSUpIiwicHJpbWFyeUJvcmRlckNvbG9yIjoiaHNsKDI0MCwgNjAlLCA4Ni4yNzQ1MDk4MDM5JSkiLCJzZWNvbmRhcnlCb3JkZXJDb2xvciI6ImhzbCg2MCwgNjAlLCA4My41Mjk0MTE3NjQ3JSkiLCJ0ZXJ0aWFyeUJvcmRlckNvbG9yIjoiaHNsKDgwLCA2MCUsIDg2LjI3NDUwOTgwMzklKSIsInByaW1hcnlUZXh0Q29sb3IiOiIjMTMxMzAwIiwic2Vjb25kYXJ5VGV4dENvbG9yIjoiIzAwMDAyMSIsInRlcnRpYXJ5VGV4dENvbG9yIjoicmdiKDkuNTAwMDAwMDAwMSwgOS41MDAwMDAwMDAxLCA5LjUwMDAwMDAwMDEpIiwibGluZUNvbG9yIjoiIzMzMzMzMyIsInRleHRDb2xvciI6IiMzMzMiLCJtYWluQmtnIjoiI0VDRUNGRiIsInNlY29uZEJrZyI6IiNmZmZmZGUiLCJib3JkZXIxIjoiIzkzNzBEQiIsImJvcmRlcjIiOiIjYWFhYTMzIiwiYXJyb3doZWFkQ29sb3IiOiIjMzMzMzMzIiwiZm9udEZhbWlseSI6IlwidHJlYnVjaGV0IG1zXCIsIHZlcmRhbmEsIGFyaWFsIiwiZm9udFNpemUiOiIxNnB4IiwibGFiZWxCYWNrZ3JvdW5kIjoiI2U4ZThlOCIsIm5vZGVCa2ciOiIjRUNFQ0ZGIiwibm9kZUJvcmRlciI6IiM5MzcwREIiLCJjbHVzdGVyQmtnIjoiI2ZmZmZkZSIsImNsdXN0ZXJCb3JkZXIiOiIjYWFhYTMzIiwiZGVmYXVsdExpbmtDb2xvciI6IiMzMzMzMzMiLCJ0aXRsZUNvbG9yIjoiIzMzMyIsImVkZ2VMYWJlbEJhY2tncm91bmQiOiIjZThlOGU4IiwiYWN0b3JCb3JkZXIiOiJoc2woMjU5LjYyNjE2ODIyNDMsIDU5Ljc3NjUzNjMxMjglLCA4Ny45MDE5NjA3ODQzJSkiLCJhY3RvckJrZyI6IiNFQ0VDRkYiLCJhY3RvclRleHRDb2xvciI6ImJsYWNrIiwiYWN0b3JMaW5lQ29sb3IiOiJncmV5Iiwic2lnbmFsQ29sb3IiOiIjMzMzIiwic2lnbmFsVGV4dENvbG9yIjoiIzMzMyIsImxhYmVsQm94QmtnQ29sb3IiOiIjRUNFQ0ZGIiwibGFiZWxCb3hCb3JkZXJDb2xvciI6ImhzbCgyNTkuNjI2MTY4MjI0MywgNTkuNzc2NTM2MzEyOCUsIDg3LjkwMTk2MDc4NDMlKSIsImxhYmVsVGV4dENvbG9yIjoiYmxhY2siLCJsb29wVGV4dENvbG9yIjoiYmxhY2siLCJub3RlQm9yZGVyQ29sb3IiOiIjYWFhYTMzIiwibm90ZUJrZ0NvbG9yIjoiI2ZmZjVhZCIsIm5vdGVUZXh0Q29sb3IiOiJibGFjayIsImFjdGl2YXRpb25Cb3JkZXJDb2xvciI6IiM2NjYiLCJhY3RpdmF0aW9uQmtnQ29sb3IiOiIjZjRmNGY0Iiwic2VxdWVuY2VOdW1iZXJDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yIjoicmdiYSgxMDIsIDEwMiwgMjU1LCAwLjQ5KSIsImFsdFNlY3Rpb25Ca2dDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yMiI6IiNmZmY0MDAiLCJ0YXNrQm9yZGVyQ29sb3IiOiIjNTM0ZmJjIiwidGFza0JrZ0NvbG9yIjoiIzhhOTBkZCIsInRhc2tUZXh0TGlnaHRDb2xvciI6IndoaXRlIiwidGFza1RleHRDb2xvciI6IndoaXRlIiwidGFza1RleHREYXJrQ29sb3IiOiJibGFjayIsInRhc2tUZXh0T3V0c2lkZUNvbG9yIjoiYmxhY2siLCJ0YXNrVGV4dENsaWNrYWJsZUNvbG9yIjoiIzAwMzE2MyIsImFjdGl2ZVRhc2tCb3JkZXJDb2xvciI6IiM1MzRmYmMiLCJhY3RpdmVUYXNrQmtnQ29sb3IiOiIjYmZjN2ZmIiwiZ3JpZENvbG9yIjoibGlnaHRncmV5IiwiZG9uZVRhc2tCa2dDb2xvciI6ImxpZ2h0Z3JleSIsImRvbmVUYXNrQm9yZGVyQ29sb3IiOiJncmV5IiwiY3JpdEJvcmRlckNvbG9yIjoiI2ZmODg4OCIsImNyaXRCa2dDb2xvciI6InJlZCIsInRvZGF5TGluZUNvbG9yIjoicmVkIiwibGFiZWxDb2xvciI6ImJsYWNrIiwiZXJyb3JCa2dDb2xvciI6IiM1NTIyMjIiLCJlcnJvclRleHRDb2xvciI6IiM1NTIyMjIiLCJjbGFzc1RleHQiOiIjMTMxMzAwIiwiZmlsbFR5cGUwIjoiI0VDRUNGRiIsImZpbGxUeXBlMSI6IiNmZmZmZGUiLCJmaWxsVHlwZTIiOiJoc2woMzA0LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTMiOiJoc2woMTI0LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkiLCJmaWxsVHlwZTQiOiJoc2woMTc2LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTUiOiJoc2woLTQsIDEwMCUsIDkzLjUyOTQxMTc2NDclKSIsImZpbGxUeXBlNiI6ImhzbCg4LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTciOiJoc2woMTg4LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkifX0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9">live editor</a>]
```
stateDiagram-v2
[*] --> Still
@@ -176,9 +193,9 @@ pie
"Rats" : 15
```
## Git graph [experimental - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2l0R3JhcGg6XG5vcHRpb25zXG57XG4gICAgXCJub2RlU3BhY2luZ1wiOiAxNTAsXG4gICAgXCJub2RlUmFkaXVzXCI6IDEwXG59XG5lbmRcbmNvbW1pdFxuYnJhbmNoIG5ld2JyYW5jaFxuY2hlY2tvdXQgbmV3YnJhbmNoXG5jb21taXRcbmNvbW1pdFxuY2hlY2tvdXQgbWFzdGVyXG5jb21taXRcbmNvbW1pdFxubWVyZ2UgbmV3YnJhbmNoXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
### Git graph [experimental - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2l0R3JhcGg6XG5vcHRpb25zXG57XG4gICAgXCJub2RlU3BhY2luZ1wiOiAxNTAsXG4gICAgXCJub2RlUmFkaXVzXCI6IDEwXG59XG5lbmRcbmNvbW1pdFxuYnJhbmNoIG5ld2JyYW5jaFxuY2hlY2tvdXQgbmV3YnJhbmNoXG5jb21taXRcbmNvbW1pdFxuY2hlY2tvdXQgbWFzdGVyXG5jb21taXRcbmNvbW1pdFxubWVyZ2UgbmV3YnJhbmNoXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
## User Journey diagram [<a href="https://mermaid-js.github.io/mermaid/#/user-journey">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
### User Journey diagram [<a href="https://mermaid-js.github.io/mermaid/#/user-journey">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
```
journey
title My working day
@@ -202,7 +219,7 @@ pie
Sit down: 3: Me
```
### Release
## Release
For those who have the permission to do so:

View File

@@ -2,13 +2,13 @@
[English](./README.md) | 简体中文
![banner](./img/header.png)
<img src="./img/header.png" alt="" />
:trophy: **Mermaid 被提名并获得了 [JS Open Source Awards (2019)](https://osawards.com/javascript/2019) 的 "The most exciting use of technology" 奖项!!!**
**感谢所有参与进来提交 PR解答疑问的人们! 🙏**
<a href="https://mermaid-js.github.io/mermaid/landing/" alt="Link to landing page for the book The Official Guide To mermaid.js"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/img/book-banner-pre-release.jpg"></a>
<a href="https://mermaid-js.github.io/mermaid/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/img/book-banner-pre-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
## 关于 Mermaid
@@ -23,7 +23,7 @@ Mermaid 通过允许用户创建便于修改的图表来解决这一难题,它
Mermaid 甚至能让非程序员也能通过 [Mermaid Live Editor](https://mermaid-js.github.io/mermaid-live-editor/) 轻松创建详细的图表。<br/>
你可以访问 [教程](./docs/Tutorials.md) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](./docs/integrations.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。
如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/n00b-overview.md) and [用法](./docs/usage.md).
如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/n00b-overview.md), [用法](./docs/usage.md) 和 [教程](./docs/Tutorials.md).
🌐 [CDN](https://unpkg.com/mermaid/) | 📖 [文档](https://mermaidjs.github.io) | 🙌 [贡献](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md) | 📜 [更新日志](./docs/CHANGELOG.md)
@@ -35,7 +35,7 @@ __下面是一些可以使用 Mermaid 创建的图表示例。点击 [语法](ht
<table>
<!-- <Flowchart> -->
## 流程图 [<a href="https://mermaid-js.github.io/mermaid/#/flowchart">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBW0hhcmRdIC0tPnxUZXh0fCBCKFJvdW5kKVxuICAgIEIgLS0-IEN7RGVjaXNpb259XG4gICAgQyAtLT58T25lfCBEW1Jlc3VsdCAxXVxuICAgIEMgLS0-fFR3b3wgRVtSZXN1bHQgMl0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
### 流程图 [<a href="https://mermaid-js.github.io/mermaid/#/flowchart">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBW0hhcmRdIC0tPnxUZXh0fCBCKFJvdW5kKVxuICAgIEIgLS0-IEN7RGVjaXNpb259XG4gICAgQyAtLT58T25lfCBEW1Jlc3VsdCAxXVxuICAgIEMgLS0-fFR3b3wgRVtSZXN1bHQgMl0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
```
flowchart LR
@@ -52,7 +52,7 @@ C -->|One| D[Result 1]
C -->|Two| E[Result 2]
```
## 时序图 [<a href="https://mermaid-js.github.io/mermaid/#/sequenceDiagram">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic2VxdWVuY2VEaWFncmFtXG5BbGljZS0-PkpvaG46IEhlbGxvIEpvaG4sIGhvdyBhcmUgeW91P1xubG9vcCBIZWFsdGhjaGVja1xuICAgIEpvaG4tPj5Kb2huOiBGaWdodCBhZ2FpbnN0IGh5cG9jaG9uZHJpYVxuZW5kXG5Ob3RlIHJpZ2h0IG9mIEpvaG46IFJhdGlvbmFsIHRob3VnaHRzIVxuSm9obi0tPj5BbGljZTogR3JlYXQhXG5Kb2huLT4-Qm9iOiBIb3cgYWJvdXQgeW91P1xuQm9iLS0-PkpvaG46IEpvbGx5IGdvb2QhIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
### 时序图 [<a href="https://mermaid-js.github.io/mermaid/#/sequenceDiagram">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic2VxdWVuY2VEaWFncmFtXG5BbGljZS0-PkpvaG46IEhlbGxvIEpvaG4sIGhvdyBhcmUgeW91P1xubG9vcCBIZWFsdGhjaGVja1xuICAgIEpvaG4tPj5Kb2huOiBGaWdodCBhZ2FpbnN0IGh5cG9jaG9uZHJpYVxuZW5kXG5Ob3RlIHJpZ2h0IG9mIEpvaG46IFJhdGlvbmFsIHRob3VnaHRzIVxuSm9obi0tPj5BbGljZTogR3JlYXQhXG5Kb2huLT4-Qm9iOiBIb3cgYWJvdXQgeW91P1xuQm9iLS0-PkpvaG46IEpvbGx5IGdvb2QhIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
```
sequenceDiagram
@@ -77,7 +77,7 @@ John->>Bob: How about you?
Bob-->>John: Jolly good!
```
## 甘特图 [<a href="https://mermaid-js.github.io/mermaid/#/gantt">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2FudHRcbnNlY3Rpb24gU2VjdGlvblxuQ29tcGxldGVkIDpkb25lLCAgICBkZXMxLCAyMDE0LTAxLTA2LDIwMTQtMDEtMDhcbkFjdGl2ZSAgICAgICAgOmFjdGl2ZSwgIGRlczIsIDIwMTQtMDEtMDcsIDNkXG5QYXJhbGxlbCAxICAgOiAgICAgICAgIGRlczMsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAyICAgOiAgICAgICAgIGRlczQsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAzICAgOiAgICAgICAgIGRlczUsIGFmdGVyIGRlczMsIDFkXG5QYXJhbGxlbCA0ICAgOiAgICAgICAgIGRlczYsIGFmdGVyIGRlczQsIDFkIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
### 甘特图 [<a href="https://mermaid-js.github.io/mermaid/#/gantt">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2FudHRcbnNlY3Rpb24gU2VjdGlvblxuQ29tcGxldGVkIDpkb25lLCAgICBkZXMxLCAyMDE0LTAxLTA2LDIwMTQtMDEtMDhcbkFjdGl2ZSAgICAgICAgOmFjdGl2ZSwgIGRlczIsIDIwMTQtMDEtMDcsIDNkXG5QYXJhbGxlbCAxICAgOiAgICAgICAgIGRlczMsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAyICAgOiAgICAgICAgIGRlczQsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAzICAgOiAgICAgICAgIGRlczUsIGFmdGVyIGRlczMsIDFkXG5QYXJhbGxlbCA0ICAgOiAgICAgICAgIGRlczYsIGFmdGVyIGRlczQsIDFkIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
```
gantt
@@ -100,7 +100,7 @@ gantt
Parallel 4 : des6, after des4, 1d
```
## 类图 [<a href="https://mermaid-js.github.io/mermaid/#/classDiagram">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiY2xhc3NEaWFncmFtXG5DbGFzczAxIDx8LS0gQXZlcnlMb25nQ2xhc3MgOiBDb29sXG48PGludGVyZmFjZT4-IENsYXNzMDFcbkNsYXNzMDkgLS0-IEMyIDogV2hlcmUgYW0gaT9cbkNsYXNzMDkgLS0qIEMzXG5DbGFzczA5IC0tfD4gQ2xhc3MwN1xuQ2xhc3MwNyA6IGVxdWFscygpXG5DbGFzczA3IDogT2JqZWN0W10gZWxlbWVudERhdGFcbkNsYXNzMDEgOiBzaXplKClcbkNsYXNzMDEgOiBpbnQgY2hpbXBcbkNsYXNzMDEgOiBpbnQgZ29yaWxsYVxuY2xhc3MgQ2xhc3MxMCB7XG4gID4-c2VydmljZT4-XG4gIGludCBpZFxuICBzaXplKClcbn0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
### 类图 [<a href="https://mermaid-js.github.io/mermaid/#/classDiagram">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiY2xhc3NEaWFncmFtXG5DbGFzczAxIDx8LS0gQXZlcnlMb25nQ2xhc3MgOiBDb29sXG48PGludGVyZmFjZT4-IENsYXNzMDFcbkNsYXNzMDkgLS0-IEMyIDogV2hlcmUgYW0gaT9cbkNsYXNzMDkgLS0qIEMzXG5DbGFzczA5IC0tfD4gQ2xhc3MwN1xuQ2xhc3MwNyA6IGVxdWFscygpXG5DbGFzczA3IDogT2JqZWN0W10gZWxlbWVudERhdGFcbkNsYXNzMDEgOiBzaXplKClcbkNsYXNzMDEgOiBpbnQgY2hpbXBcbkNsYXNzMDEgOiBpbnQgZ29yaWxsYVxuY2xhc3MgQ2xhc3MxMCB7XG4gID4-c2VydmljZT4-XG4gIGludCBpZFxuICBzaXplKClcbn0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
```
classDiagram
@@ -139,7 +139,7 @@ class Class10 {
}
```
## 状态图 [<a href="https://mermaid-js.github.io/mermaid/#/stateDiagram">文档</a> - <a href="https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtLXYyXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQiLCJ0aGVtZVZhcmlhYmxlcyI6eyJiYWNrZ3JvdW5kIjoid2hpdGUiLCJwcmltYXJ5Q29sb3IiOiIjRUNFQ0ZGIiwic2Vjb25kYXJ5Q29sb3IiOiIjZmZmZmRlIiwidGVydGlhcnlDb2xvciI6ImhzbCg4MCwgMTAwJSwgOTYuMjc0NTA5ODAzOSUpIiwicHJpbWFyeUJvcmRlckNvbG9yIjoiaHNsKDI0MCwgNjAlLCA4Ni4yNzQ1MDk4MDM5JSkiLCJzZWNvbmRhcnlCb3JkZXJDb2xvciI6ImhzbCg2MCwgNjAlLCA4My41Mjk0MTE3NjQ3JSkiLCJ0ZXJ0aWFyeUJvcmRlckNvbG9yIjoiaHNsKDgwLCA2MCUsIDg2LjI3NDUwOTgwMzklKSIsInByaW1hcnlUZXh0Q29sb3IiOiIjMTMxMzAwIiwic2Vjb25kYXJ5VGV4dENvbG9yIjoiIzAwMDAyMSIsInRlcnRpYXJ5VGV4dENvbG9yIjoicmdiKDkuNTAwMDAwMDAwMSwgOS41MDAwMDAwMDAxLCA5LjUwMDAwMDAwMDEpIiwibGluZUNvbG9yIjoiIzMzMzMzMyIsInRleHRDb2xvciI6IiMzMzMiLCJtYWluQmtnIjoiI0VDRUNGRiIsInNlY29uZEJrZyI6IiNmZmZmZGUiLCJib3JkZXIxIjoiIzkzNzBEQiIsImJvcmRlcjIiOiIjYWFhYTMzIiwiYXJyb3doZWFkQ29sb3IiOiIjMzMzMzMzIiwiZm9udEZhbWlseSI6IlwidHJlYnVjaGV0IG1zXCIsIHZlcmRhbmEsIGFyaWFsIiwiZm9udFNpemUiOiIxNnB4IiwibGFiZWxCYWNrZ3JvdW5kIjoiI2U4ZThlOCIsIm5vZGVCa2ciOiIjRUNFQ0ZGIiwibm9kZUJvcmRlciI6IiM5MzcwREIiLCJjbHVzdGVyQmtnIjoiI2ZmZmZkZSIsImNsdXN0ZXJCb3JkZXIiOiIjYWFhYTMzIiwiZGVmYXVsdExpbmtDb2xvciI6IiMzMzMzMzMiLCJ0aXRsZUNvbG9yIjoiIzMzMyIsImVkZ2VMYWJlbEJhY2tncm91bmQiOiIjZThlOGU4IiwiYWN0b3JCb3JkZXIiOiJoc2woMjU5LjYyNjE2ODIyNDMsIDU5Ljc3NjUzNjMxMjglLCA4Ny45MDE5NjA3ODQzJSkiLCJhY3RvckJrZyI6IiNFQ0VDRkYiLCJhY3RvclRleHRDb2xvciI6ImJsYWNrIiwiYWN0b3JMaW5lQ29sb3IiOiJncmV5Iiwic2lnbmFsQ29sb3IiOiIjMzMzIiwic2lnbmFsVGV4dENvbG9yIjoiIzMzMyIsImxhYmVsQm94QmtnQ29sb3IiOiIjRUNFQ0ZGIiwibGFiZWxCb3hCb3JkZXJDb2xvciI6ImhzbCgyNTkuNjI2MTY4MjI0MywgNTkuNzc2NTM2MzEyOCUsIDg3LjkwMTk2MDc4NDMlKSIsImxhYmVsVGV4dENvbG9yIjoiYmxhY2siLCJsb29wVGV4dENvbG9yIjoiYmxhY2siLCJub3RlQm9yZGVyQ29sb3IiOiIjYWFhYTMzIiwibm90ZUJrZ0NvbG9yIjoiI2ZmZjVhZCIsIm5vdGVUZXh0Q29sb3IiOiJibGFjayIsImFjdGl2YXRpb25Cb3JkZXJDb2xvciI6IiM2NjYiLCJhY3RpdmF0aW9uQmtnQ29sb3IiOiIjZjRmNGY0Iiwic2VxdWVuY2VOdW1iZXJDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yIjoicmdiYSgxMDIsIDEwMiwgMjU1LCAwLjQ5KSIsImFsdFNlY3Rpb25Ca2dDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yMiI6IiNmZmY0MDAiLCJ0YXNrQm9yZGVyQ29sb3IiOiIjNTM0ZmJjIiwidGFza0JrZ0NvbG9yIjoiIzhhOTBkZCIsInRhc2tUZXh0TGlnaHRDb2xvciI6IndoaXRlIiwidGFza1RleHRDb2xvciI6IndoaXRlIiwidGFza1RleHREYXJrQ29sb3IiOiJibGFjayIsInRhc2tUZXh0T3V0c2lkZUNvbG9yIjoiYmxhY2siLCJ0YXNrVGV4dENsaWNrYWJsZUNvbG9yIjoiIzAwMzE2MyIsImFjdGl2ZVRhc2tCb3JkZXJDb2xvciI6IiM1MzRmYmMiLCJhY3RpdmVUYXNrQmtnQ29sb3IiOiIjYmZjN2ZmIiwiZ3JpZENvbG9yIjoibGlnaHRncmV5IiwiZG9uZVRhc2tCa2dDb2xvciI6ImxpZ2h0Z3JleSIsImRvbmVUYXNrQm9yZGVyQ29sb3IiOiJncmV5IiwiY3JpdEJvcmRlckNvbG9yIjoiI2ZmODg4OCIsImNyaXRCa2dDb2xvciI6InJlZCIsInRvZGF5TGluZUNvbG9yIjoicmVkIiwibGFiZWxDb2xvciI6ImJsYWNrIiwiZXJyb3JCa2dDb2xvciI6IiM1NTIyMjIiLCJlcnJvclRleHRDb2xvciI6IiM1NTIyMjIiLCJjbGFzc1RleHQiOiIjMTMxMzAwIiwiZmlsbFR5cGUwIjoiI0VDRUNGRiIsImZpbGxUeXBlMSI6IiNmZmZmZGUiLCJmaWxsVHlwZTIiOiJoc2woMzA0LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTMiOiJoc2woMTI0LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkiLCJmaWxsVHlwZTQiOiJoc2woMTc2LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTUiOiJoc2woLTQsIDEwMCUsIDkzLjUyOTQxMTc2NDclKSIsImZpbGxUeXBlNiI6ImhzbCg4LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTciOiJoc2woMTg4LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkifX0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9">live editor</a>]
### 状态图 [[<a href="https://mermaid-js.github.io/mermaid/#/stateDiagram">docs</a> - <a href="https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtLXYyXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQiLCJ0aGVtZVZhcmlhYmxlcyI6eyJiYWNrZ3JvdW5kIjoid2hpdGUiLCJwcmltYXJ5Q29sb3IiOiIjRUNFQ0ZGIiwic2Vjb25kYXJ5Q29sb3IiOiIjZmZmZmRlIiwidGVydGlhcnlDb2xvciI6ImhzbCg4MCwgMTAwJSwgOTYuMjc0NTA5ODAzOSUpIiwicHJpbWFyeUJvcmRlckNvbG9yIjoiaHNsKDI0MCwgNjAlLCA4Ni4yNzQ1MDk4MDM5JSkiLCJzZWNvbmRhcnlCb3JkZXJDb2xvciI6ImhzbCg2MCwgNjAlLCA4My41Mjk0MTE3NjQ3JSkiLCJ0ZXJ0aWFyeUJvcmRlckNvbG9yIjoiaHNsKDgwLCA2MCUsIDg2LjI3NDUwOTgwMzklKSIsInByaW1hcnlUZXh0Q29sb3IiOiIjMTMxMzAwIiwic2Vjb25kYXJ5VGV4dENvbG9yIjoiIzAwMDAyMSIsInRlcnRpYXJ5VGV4dENvbG9yIjoicmdiKDkuNTAwMDAwMDAwMSwgOS41MDAwMDAwMDAxLCA5LjUwMDAwMDAwMDEpIiwibGluZUNvbG9yIjoiIzMzMzMzMyIsInRleHRDb2xvciI6IiMzMzMiLCJtYWluQmtnIjoiI0VDRUNGRiIsInNlY29uZEJrZyI6IiNmZmZmZGUiLCJib3JkZXIxIjoiIzkzNzBEQiIsImJvcmRlcjIiOiIjYWFhYTMzIiwiYXJyb3doZWFkQ29sb3IiOiIjMzMzMzMzIiwiZm9udEZhbWlseSI6IlwidHJlYnVjaGV0IG1zXCIsIHZlcmRhbmEsIGFyaWFsIiwiZm9udFNpemUiOiIxNnB4IiwibGFiZWxCYWNrZ3JvdW5kIjoiI2U4ZThlOCIsIm5vZGVCa2ciOiIjRUNFQ0ZGIiwibm9kZUJvcmRlciI6IiM5MzcwREIiLCJjbHVzdGVyQmtnIjoiI2ZmZmZkZSIsImNsdXN0ZXJCb3JkZXIiOiIjYWFhYTMzIiwiZGVmYXVsdExpbmtDb2xvciI6IiMzMzMzMzMiLCJ0aXRsZUNvbG9yIjoiIzMzMyIsImVkZ2VMYWJlbEJhY2tncm91bmQiOiIjZThlOGU4IiwiYWN0b3JCb3JkZXIiOiJoc2woMjU5LjYyNjE2ODIyNDMsIDU5Ljc3NjUzNjMxMjglLCA4Ny45MDE5NjA3ODQzJSkiLCJhY3RvckJrZyI6IiNFQ0VDRkYiLCJhY3RvclRleHRDb2xvciI6ImJsYWNrIiwiYWN0b3JMaW5lQ29sb3IiOiJncmV5Iiwic2lnbmFsQ29sb3IiOiIjMzMzIiwic2lnbmFsVGV4dENvbG9yIjoiIzMzMyIsImxhYmVsQm94QmtnQ29sb3IiOiIjRUNFQ0ZGIiwibGFiZWxCb3hCb3JkZXJDb2xvciI6ImhzbCgyNTkuNjI2MTY4MjI0MywgNTkuNzc2NTM2MzEyOCUsIDg3LjkwMTk2MDc4NDMlKSIsImxhYmVsVGV4dENvbG9yIjoiYmxhY2siLCJsb29wVGV4dENvbG9yIjoiYmxhY2siLCJub3RlQm9yZGVyQ29sb3IiOiIjYWFhYTMzIiwibm90ZUJrZ0NvbG9yIjoiI2ZmZjVhZCIsIm5vdGVUZXh0Q29sb3IiOiJibGFjayIsImFjdGl2YXRpb25Cb3JkZXJDb2xvciI6IiM2NjYiLCJhY3RpdmF0aW9uQmtnQ29sb3IiOiIjZjRmNGY0Iiwic2VxdWVuY2VOdW1iZXJDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yIjoicmdiYSgxMDIsIDEwMiwgMjU1LCAwLjQ5KSIsImFsdFNlY3Rpb25Ca2dDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yMiI6IiNmZmY0MDAiLCJ0YXNrQm9yZGVyQ29sb3IiOiIjNTM0ZmJjIiwidGFza0JrZ0NvbG9yIjoiIzhhOTBkZCIsInRhc2tUZXh0TGlnaHRDb2xvciI6IndoaXRlIiwidGFza1RleHRDb2xvciI6IndoaXRlIiwidGFza1RleHREYXJrQ29sb3IiOiJibGFjayIsInRhc2tUZXh0T3V0c2lkZUNvbG9yIjoiYmxhY2siLCJ0YXNrVGV4dENsaWNrYWJsZUNvbG9yIjoiIzAwMzE2MyIsImFjdGl2ZVRhc2tCb3JkZXJDb2xvciI6IiM1MzRmYmMiLCJhY3RpdmVUYXNrQmtnQ29sb3IiOiIjYmZjN2ZmIiwiZ3JpZENvbG9yIjoibGlnaHRncmV5IiwiZG9uZVRhc2tCa2dDb2xvciI6ImxpZ2h0Z3JleSIsImRvbmVUYXNrQm9yZGVyQ29sb3IiOiJncmV5IiwiY3JpdEJvcmRlckNvbG9yIjoiI2ZmODg4OCIsImNyaXRCa2dDb2xvciI6InJlZCIsInRvZGF5TGluZUNvbG9yIjoicmVkIiwibGFiZWxDb2xvciI6ImJsYWNrIiwiZXJyb3JCa2dDb2xvciI6IiM1NTIyMjIiLCJlcnJvclRleHRDb2xvciI6IiM1NTIyMjIiLCJjbGFzc1RleHQiOiIjMTMxMzAwIiwiZmlsbFR5cGUwIjoiI0VDRUNGRiIsImZpbGxUeXBlMSI6IiNmZmZmZGUiLCJmaWxsVHlwZTIiOiJoc2woMzA0LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTMiOiJoc2woMTI0LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkiLCJmaWxsVHlwZTQiOiJoc2woMTc2LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTUiOiJoc2woLTQsIDEwMCUsIDkzLjUyOTQxMTc2NDclKSIsImZpbGxUeXBlNiI6ImhzbCg4LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTciOiJoc2woMTg4LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkifX0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9">live editor</a>]
```
stateDiagram-v2
@@ -160,7 +160,7 @@ Moving --> Crash
Crash --> [*]
```
## 饼图 [<a href="https://mermaid-js.github.io/mermaid/#/pie">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoicGllXG5cIkRvZ3NcIiA6IDQyLjk2XG5cIkNhdHNcIiA6IDUwLjA1XG5cIlJhdHNcIiA6IDEwLjAxIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
### 饼图 [<a href="https://mermaid-js.github.io/mermaid/#/pie">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoicGllXG5cIkRvZ3NcIiA6IDQyLjk2XG5cIkNhdHNcIiA6IDUwLjA1XG5cIlJhdHNcIiA6IDEwLjAxIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
```
pie
@@ -175,9 +175,9 @@ pie
"Rats" : 15
```
## Git图 [实验特性 - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2l0R3JhcGg6XG5vcHRpb25zXG57XG4gICAgXCJub2RlU3BhY2luZ1wiOiAxNTAsXG4gICAgXCJub2RlUmFkaXVzXCI6IDEwXG59XG5lbmRcbmNvbW1pdFxuYnJhbmNoIG5ld2JyYW5jaFxuY2hlY2tvdXQgbmV3YnJhbmNoXG5jb21taXRcbmNvbW1pdFxuY2hlY2tvdXQgbWFzdGVyXG5jb21taXRcbmNvbW1pdFxubWVyZ2UgbmV3YnJhbmNoXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
### Git图 [实验特性 - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2l0R3JhcGg6XG5vcHRpb25zXG57XG4gICAgXCJub2RlU3BhY2luZ1wiOiAxNTAsXG4gICAgXCJub2RlUmFkaXVzXCI6IDEwXG59XG5lbmRcbmNvbW1pdFxuYnJhbmNoIG5ld2JyYW5jaFxuY2hlY2tvdXQgbmV3YnJhbmNoXG5jb21taXRcbmNvbW1pdFxuY2hlY2tvdXQgbWFzdGVyXG5jb21taXRcbmNvbW1pdFxubWVyZ2UgbmV3YnJhbmNoXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
## 用户体验旅程图 [<a href="https://mermaid-js.github.io/mermaid/#/user-journey">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
### 用户体验旅程图 [<a href="https://mermaid-js.github.io/mermaid/#/user-journey">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
```
journey
@@ -202,7 +202,7 @@ pie
Sit down: 3: Me
```
### 发布
## 发布
对于有权限的同学来说,你可以通过以下步骤来完成发布操作:

16
applitools.cnfig.js Normal file
View File

@@ -0,0 +1,16 @@
module.exports = {
testConcurrency: 1,
// browser: [
// // Add browsers with different viewports
// { width: 800, height: 600, name: 'chrome' },
// { width: 700, height: 500, name: 'firefox' },
// { width: 1600, height: 1200, name: 'ie11' },
// { width: 1024, height: 768, name: 'edgechromium' },
// { width: 800, height: 600, name: 'safari' },
// // Add mobile emulation devices in Portrait mode
// { deviceName: 'iPhone X', screenOrientation: 'portrait' },
// { deviceName: 'Pixel 2', screenOrientation: 'portrait' },
// ],
// // set batch name to the configuration
// batchName: 'Ultrafast Batch',
};

20
cypress.config.js Normal file
View File

@@ -0,0 +1,20 @@
const { defineConfig } = require('cypress');
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
require('@applitools/eyes-cypress')(module);
module.exports = defineConfig({
e2e: {
specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
setupNodeEvents(on, config) {
addMatchImageSnapshotPlugin(on, config);
// copy any needed variables from process.env to config.env
config.env.useAppli = process.env.USE_APPLI ? true : false;
config.env.codeBranch = process.env.APPLI_BRANCH;
// do not forget to return the changed config object!
return config;
},
supportFile: 'cypress/support/index.js',
},
video: false,
});

View File

@@ -1,3 +0,0 @@
{
"video": false
}

View File

@@ -115,4 +115,18 @@ describe('XSS', () => {
cy.wait(1000);
cy.get('#the-malware').should('not.exist');
});
it('should sanitize colons properly', () => {
cy.visit('http://localhost:9000/xss20.html');
cy.wait(1000);
cy.get('a').click('');
cy.wait(1000);
cy.get('#the-malware').should('not.exist');
});
it('should sanitize colons properly', () => {
cy.visit('http://localhost:9000/xss21.html');
cy.wait(1000);
cy.get('a').click('');
cy.wait(1000);
cy.get('#the-malware').should('not.exist');
});
});

View File

@@ -0,0 +1,59 @@
import { imgSnapshotTest } from '../../helpers/util.js';
describe('Git Graph diagram', () => {
it('1: should render a simple gitgraph with commit on main branch', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
commit id: "3"
`,
{}
);
});
// it(`ultraFastTest`, function () {
// // Navigate to the url we want to test
// // ⭐️ Note to see visual bugs, run the test using the above URL for the 1st run.
// // but then change the above URL to https://demo.applitools.com/index_v2.html
// // (for the 2nd run)
// cy.visit('https://demo.applitools.com');
// // Call Open on eyes to initialize a test session
// cy.eyesOpen({
// appName: 'Demo App',
// testName: 'Ultrafast grid demo',
// });
// // check the login page with fluent api, see more info here
// // https://applitools.com/docs/topics/sdk/the-eyes-sdk-check-fluent-api.html
// cy.eyesCheckWindow({
// tag: 'Login Window',
// target: 'window',
// fully: true,
// });
// cy.get('#log-in').click();
// // Check the app page
// cy.eyesCheckWindow({
// tag: 'App Window',
// target: 'window',
// fully: true,
// });
// // Call Close on eyes to let the server know it should display the results
// cy.eyesClose();
// });
// it('works', () => {
// cy.visit('https://applitools.com/helloworld');
// cy.eyesOpen({
// appName: 'Hello World!',
// testName: 'My first JavaScript test!',
// browser: { width: 800, height: 600 },
// });
// cy.eyesCheckWindow('Main Page');
// cy.get('button').click();
// cy.eyesCheckWindow('Click!');
// cy.eyesClose();
// });
});

View File

@@ -1,410 +1,410 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util';
describe('Class diagram', () => {
it('1: should render a simple class diagram', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class12 <|.. Class08
Class11 ..>Class12
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{ logLevel: 1 }
);
cy.get('svg');
});
it('2: should render a simple class diagrams with cardinality', () => {
imgSnapshotTest(
`
classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('3: should render a simple class diagram with different visibilities', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class01 : -privateMethod()
Class01 : +publicMethod()
Class01 : #protectedMethod()
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
`,
{}
);
cy.get('svg');
});
it('4: should render a simple class diagram with comments', () => {
imgSnapshotTest(
`
classDiagram
%% this is a comment
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('5: should render a simple class diagram with abstract method', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 : someMethod()*
`,
{}
);
cy.get('svg');
});
it('6: should render a simple class diagram with static method', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 : someMethod()$
`,
{}
);
cy.get('svg');
});
it('7: should render a simple class diagram with Generic class', () => {
imgSnapshotTest(
`
classDiagram
class Class01~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('8: should render a simple class diagram with Generic class and relations', () => {
imgSnapshotTest(
`
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('9: should render a simple class diagram with clickable link', () => {
imgSnapshotTest(
`
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
link Class01 "google.com" "A Tooltip"
`,
{}
);
cy.get('svg');
});
it('10: should render a simple class diagram with clickable callback', () => {
imgSnapshotTest(
`
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
callback Class01 "functionCall" "A Tooltip"
`,
{}
);
cy.get('svg');
});
it('11: should render a simple class diagram with return type on method', () => {
imgSnapshotTest(
`
classDiagram
class Class10~T~ {
int[] id
test(int[] ids) bool
testArray() bool[]
}
`,
{}
);
cy.get('svg');
});
it('12: should render a simple class diagram with generic types', () => {
imgSnapshotTest(
`
classDiagram
class Class10~T~ {
int[] id
List~int~ ids
test(List~int~ ids) List~bool~
testArray() bool[]
}
`,
{}
);
cy.get('svg');
});
it('13: should render a simple class diagram with css classes applied', () => {
imgSnapshotTest(
`
classDiagram
class Class10 {
int[] id
List~int~ ids
test(List~int~ ids) List~bool~
testArray() bool[]
}
class Class10:::exClass2
`,
{}
);
cy.get('svg');
});
it('14: should render a simple class diagram with css classes applied directly', () => {
imgSnapshotTest(
`
classDiagram
class Class10:::exClass2 {
int[] id
List~int~ ids
test(List~int~ ids) List~bool~
testArray() bool[]
}
`,
{}
);
cy.get('svg');
});
it('15: should render a simple class diagram with css classes applied two multiple classes', () => {
imgSnapshotTest(
`
classDiagram
class Class10
class Class20
cssClass "Class10, Class20" exClass2
class Class20:::exClass2
`,
{}
);
cy.get('svg');
});
it('16: should render multiple class diagrams', () => {
imgSnapshotTest(
[
`
classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
`
classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
],
{}
);
cy.get('svg');
});
// it('17: should render a class diagram when useMaxWidth is true (default)', () => {
// renderGraph(
// `
// classDiagram
// Class01 <|-- AveryLongClass : Cool
// Class01 : size()
// Class01 : int chimp
// Class01 : int gorilla
// Class01 : -int privateChimp
// Class01 : +int publicGorilla
// Class01 : #int protectedMarmoset
// `,
// { class: { useMaxWidth: true } }
// );
// cy.get('svg')
// .should((svg) => {
// expect(svg).to.have.attr('width', '100%');
// const height = parseFloat(svg.attr('height'));
// expect(height).to.be.within(332, 333);
// // expect(svg).to.have.attr('height', '218');
// const style = svg.attr('style');
// expect(style).to.match(/^max-width: [\d.]+px;$/);
// const maxWidthValue = parseInt(style.match(/[\d.]+/g).join(''));
// // use within because the absolute value can be slightly different depending on the environment ±5%
// expect(maxWidthValue).to.be.within(203, 204);
// });
// });
// it('18: should render a class diagram when useMaxWidth is false', () => {
// renderGraph(
// `
// classDiagram
// Class01 <|-- AveryLongClass : Cool
// Class01 : size()
// Class01 : int chimp
// Class01 : int gorilla
// Class01 : -int privateChimp
// Class01 : +int publicGorilla
// Class01 : #int protectedMarmoset
// `,
// { class: { useMaxWidth: false } }
// );
// cy.get('svg')
// .should((svg) => {
// const width = parseFloat(svg.attr('width'));
// // use within because the absolute value can be slightly different depending on the environment ±5%
// expect(width).to.be.within(100, 101);
// const height = parseFloat(svg.attr('height'));
// expect(height).to.be.within(332, 333);
// // expect(svg).to.have.attr('height', '332');
// // expect(svg).to.not.have.attr('style');
// });
// });
});
import { imgSnapshotTest, renderGraph } from '../../helpers/util';
describe('Class diagram', () => {
it('1: should render a simple class diagram', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class12 <|.. Class08
Class11 ..>Class12
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{ logLevel: 1 }
);
cy.get('svg');
});
it('2: should render a simple class diagrams with cardinality', () => {
imgSnapshotTest(
`
classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('3: should render a simple class diagram with different visibilities', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class01 : -privateMethod()
Class01 : +publicMethod()
Class01 : #protectedMethod()
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
`,
{}
);
cy.get('svg');
});
it('4: should render a simple class diagram with comments', () => {
imgSnapshotTest(
`
classDiagram
%% this is a comment
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('5: should render a simple class diagram with abstract method', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 : someMethod()*
`,
{}
);
cy.get('svg');
});
it('6: should render a simple class diagram with static method', () => {
imgSnapshotTest(
`
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 : someMethod()$
`,
{}
);
cy.get('svg');
});
it('7: should render a simple class diagram with Generic class', () => {
imgSnapshotTest(
`
classDiagram
class Class01~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('8: should render a simple class diagram with Generic class and relations', () => {
imgSnapshotTest(
`
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
{}
);
cy.get('svg');
});
it('9: should render a simple class diagram with clickable link', () => {
imgSnapshotTest(
`
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
link Class01 "google.com" "A Tooltip"
`,
{}
);
cy.get('svg');
});
it('10: should render a simple class diagram with clickable callback', () => {
imgSnapshotTest(
`
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class03~T~ *-- Class04~T~
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 <--> C2: Cool label
class Class10~T~ {
&lt;&lt;service&gt;&gt;
int id
test()
}
callback Class01 "functionCall" "A Tooltip"
`,
{}
);
cy.get('svg');
});
it('11: should render a simple class diagram with return type on method', () => {
imgSnapshotTest(
`
classDiagram
class Class10~T~ {
int[] id
test(int[] ids) bool
testArray() bool[]
}
`,
{}
);
cy.get('svg');
});
it('12: should render a simple class diagram with generic types', () => {
imgSnapshotTest(
`
classDiagram
class Class10~T~ {
int[] id
List~int~ ids
test(List~int~ ids) List~bool~
testArray() bool[]
}
`,
{}
);
cy.get('svg');
});
it('13: should render a simple class diagram with css classes applied', () => {
imgSnapshotTest(
`
classDiagram
class Class10 {
int[] id
List~int~ ids
test(List~int~ ids) List~bool~
testArray() bool[]
}
class Class10:::exClass2
`,
{}
);
cy.get('svg');
});
it('14: should render a simple class diagram with css classes applied directly', () => {
imgSnapshotTest(
`
classDiagram
class Class10:::exClass2 {
int[] id
List~int~ ids
test(List~int~ ids) List~bool~
testArray() bool[]
}
`,
{}
);
cy.get('svg');
});
it('15: should render a simple class diagram with css classes applied two multiple classes', () => {
imgSnapshotTest(
`
classDiagram
class Class10
class Class20
cssClass "Class10, Class20" exClass2
class Class20:::exClass2
`,
{}
);
cy.get('svg');
});
it('16: should render multiple class diagrams', () => {
imgSnapshotTest(
[
`
classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
`
classDiagram
Class01 "1" <|--|> "*" AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class08 "1" <--> "*" C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
`,
],
{}
);
cy.get('svg');
});
// it('17: should render a class diagram when useMaxWidth is true (default)', () => {
// renderGraph(
// `
// classDiagram
// Class01 <|-- AveryLongClass : Cool
// Class01 : size()
// Class01 : int chimp
// Class01 : int gorilla
// Class01 : -int privateChimp
// Class01 : +int publicGorilla
// Class01 : #int protectedMarmoset
// `,
// { class: { useMaxWidth: true } }
// );
// cy.get('svg')
// .should((svg) => {
// expect(svg).to.have.attr('width', '100%');
// const height = parseFloat(svg.attr('height'));
// expect(height).to.be.within(332, 333);
// // expect(svg).to.have.attr('height', '218');
// const style = svg.attr('style');
// expect(style).to.match(/^max-width: [\d.]+px;$/);
// const maxWidthValue = parseInt(style.match(/[\d.]+/g).join(''));
// // use within because the absolute value can be slightly different depending on the environment ±5%
// expect(maxWidthValue).to.be.within(203, 204);
// });
// });
// it('18: should render a class diagram when useMaxWidth is false', () => {
// renderGraph(
// `
// classDiagram
// Class01 <|-- AveryLongClass : Cool
// Class01 : size()
// Class01 : int chimp
// Class01 : int gorilla
// Class01 : -int privateChimp
// Class01 : +int publicGorilla
// Class01 : #int protectedMarmoset
// `,
// { class: { useMaxWidth: false } }
// );
// cy.get('svg')
// .should((svg) => {
// const width = parseFloat(svg.attr('width'));
// // use within because the absolute value can be slightly different depending on the environment ±5%
// expect(width).to.be.within(100, 101);
// const height = parseFloat(svg.attr('height'));
// expect(height).to.be.within(332, 333);
// // expect(svg).to.have.attr('height', '332');
// // expect(svg).to.not.have.attr('style');
// });
// });
});

View File

@@ -291,4 +291,36 @@ describe('Gantt diagram', () => {
{ gantt: { topAxis: true } }
);
});
it('should render accessibility tags', function () {
const expectedTitle = 'Gantt Diagram';
const expectedAccDescription = 'Tasks for Q4';
renderGraph(
`
gantt
accTitle: ${expectedTitle}
accDescr: ${expectedAccDescription}
dateFormat YYYY-MM-DD
section Section
A task :a1, 2014-01-01, 30d
`,
{}
);
cy.get('svg').should((svg) => {
const el = svg.get(0);
const children = Array.from(el.children);
const titleEl = children.find(function (node) {
return node.tagName === 'title';
});
const descriptionEl = children.find(function (node) {
return node.tagName === 'desc';
});
expect(titleEl).to.exist;
expect(titleEl.textContent).to.equal(expectedTitle);
expect(descriptionEl).to.exist;
expect(descriptionEl.textContent).to.equal(expectedAccDescription);
});
});
});

View File

@@ -0,0 +1,210 @@
import { imgSnapshotTest } from '../../helpers/util.js';
describe('Git Graph diagram', () => {
it('1: should render a simple gitgraph with commit on main branch', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
commit id: "3"
`,
{}
);
});
it('2: should render a simple gitgraph with commit on main branch with Id', () => {
imgSnapshotTest(
`gitGraph
commit id: "One"
commit id: "Two"
commit id: "Three"
`,
{}
);
});
it('3: should render a simple gitgraph with different commitTypes on main branch ', () => {
imgSnapshotTest(
`gitGraph
commit id: "Normal Commit"
commit id: "Reverse Commit" type: REVERSE
commit id: "Hightlight Commit" type: HIGHLIGHT
`,
{}
);
});
it('4: should render a simple gitgraph with tags commitTypes on main branch ', () => {
imgSnapshotTest(
`gitGraph
commit id: "Normal Commit with tag" tag: "v1.0.0"
commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1"
commit id: "Hightlight Commit" type: HIGHLIGHT tag: "8.8.4"
`,
{}
);
});
it('5: should render a simple gitgraph with two branches', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
branch develop
checkout develop
commit id: "3"
commit id: "4"
checkout main
commit id: "5"
commit id: "6"
`,
{}
);
});
it('6: should render a simple gitgraph with two branches and merge commit', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
branch develop
checkout develop
commit id: "3"
commit id: "4"
checkout main
merge develop
commit id: "5"
commit id: "6"
`,
{}
);
});
it('7: should render a simple gitgraph with three branches and merge commit', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
branch nice_feature
checkout nice_feature
commit id: "3"
checkout main
commit id: "4"
checkout nice_feature
branch very_nice_feature
checkout very_nice_feature
commit id: "5"
checkout main
commit id: "6"
checkout nice_feature
commit id: "7"
checkout main
merge nice_feature
checkout very_nice_feature
commit id: "8"
checkout main
commit id: "9"
`,
{}
);
});
it('8: should render a simple gitgraph with more than 8 branchs & overriding variables', () => {
imgSnapshotTest(
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
'gitBranchLabel0': '#ffffff',
'gitBranchLabel1': '#ffffff',
'gitBranchLabel2': '#ffffff',
'gitBranchLabel3': '#ffffff',
'gitBranchLabel4': '#ffffff',
'gitBranchLabel5': '#ffffff',
'gitBranchLabel6': '#ffffff',
'gitBranchLabel7': '#ffffff',
} } }%%
gitGraph
checkout main
branch branch1
branch branch2
branch branch3
branch branch4
branch branch5
branch branch6
branch branch7
branch branch8
branch branch9
checkout branch1
commit id: "1"
`,
{}
);
});
it('9: should render a simple gitgraph with rotated labels', () => {
imgSnapshotTest(
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'gitGraph': {
'rotateCommitLabel': true
} } }%%
gitGraph
commit id: "75f7219e83b321cd3fdde7dcf83bc7c1000a6828"
commit id: "0db4784daf82736dec4569e0dc92980d328c1f2e"
commit id: "7067e9973f9eaa6cd4a4b723c506d1eab598e83e"
commit id: "66972321ad6c199013b5b31f03b3a86fa3f9817d"
`,
{}
);
});
it('10: should render a simple gitgraph with horizontal labels', () => {
imgSnapshotTest(
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'gitGraph': {
'rotateCommitLabel': false
} } }%%
gitGraph
commit id: "Alpha"
commit id: "Beta"
commit id: "Gamma"
commit id: "Delta"
`,
{}
);
});
it('11: should render a simple gitgraph with cherry pick commit', () => {
imgSnapshotTest(
`
gitGraph
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
checkout develop
commit id:"C"
`,
{}
);
});
it('11: should render a simple gitgraph with two cherry pick commit', () => {
imgSnapshotTest(
`
gitGraph
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
branch featureA
commit id:"FIX"
commit id: "FIX-2"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
cherry-pick id:"FIX"
checkout develop
commit id:"C"
merge featureA
`,
{}
);
});
});

View File

@@ -0,0 +1,114 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js';
describe('Requirement diagram', () => {
it('sample', () => {
imgSnapshotTest(
`
requirementDiagram
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
functionalRequirement test_req2 {
id: 1.1
text: the second test text.
risk: low
verifymethod: inspection
}
performanceRequirement test_req3 {
id: 1.2
text: the third test text.
risk: medium
verifymethod: demonstration
}
element test_entity {
type: simulation
}
element test_entity2 {
type: word doc
docRef: reqs/test_entity
}
test_entity - satisfies -> test_req2
test_req - traces -> test_req2
test_req - contains -> test_req3
test_req <- copies - test_entity2
`,
{}
);
cy.get('svg');
});
it('should render accessibility tags', function () {
const expectedTitle = 'Gantt Diagram';
const expectedAccDescription = 'Tasks for Q4';
renderGraph(
`
requirementDiagram
accTitle: ${expectedTitle}
accDescr: ${expectedAccDescription}
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
functionalRequirement test_req2 {
id: 1.1
text: the second test text.
risk: low
verifymethod: inspection
}
performanceRequirement test_req3 {
id: 1.2
text: the third test text.
risk: medium
verifymethod: demonstration
}
element test_entity {
type: simulation
}
element test_entity2 {
type: word doc
docRef: reqs/test_entity
}
test_entity - satisfies -> test_req2
test_req - traces -> test_req2
test_req - contains -> test_req3
test_req <- copies - test_entity2
`,
{}
);
cy.get('svg').should((svg) => {
const el = svg.get(0);
const children = Array.from(el.children);
const titleEl = children.find(function (node) {
return node.tagName === 'title';
});
const descriptionEl = children.find(function (node) {
return node.tagName === 'desc';
});
expect(titleEl).to.exist;
expect(titleEl.textContent).to.equal(expectedTitle);
expect(descriptionEl).to.exist;
expect(descriptionEl.textContent).to.equal(expectedAccDescription);
});
});
});

View File

@@ -452,6 +452,42 @@ context('Sequence diagram', () => {
{}
);
});
it('should render rect around and inside criticals', () => {
imgSnapshotTest(
`
sequenceDiagram
A ->> B: 1
rect rgb(204, 0, 102)
critical yes
C ->> C: 1
option no
rect rgb(0, 204, 204)
C ->> C: 0
end
end
end
B ->> A: Return
`,
{}
);
});
it('should render rect around and inside breaks', () => {
imgSnapshotTest(
`
sequenceDiagram
A ->> B: 1
rect rgb(204, 0, 102)
break yes
rect rgb(0, 204, 204)
C ->> C: 0
end
end
end
B ->> A: Return
`,
{}
);
});
it('should render autonumber when configured with such', () => {
imgSnapshotTest(
`
@@ -610,6 +646,20 @@ context('Sequence diagram', () => {
}
);
});
it("shouldn't display unused participants", () => {
//Be aware that the syntax for "properties" is likely to be changed.
imgSnapshotTest(
`
%%{init: { "config": { "sequence": {"hideUnusedParticipants": true }}}}%%
sequenceDiagram
participant a
`,
{
logLevel: 0,
sequence: { mirrorActors: false, noteFontSize: 18, noteFontFamily: 'Arial' },
}
);
});
});
context('svg size', () => {
it('should render a sequence diagram when useMaxWidth is true (default)', () => {
@@ -644,7 +694,7 @@ context('Sequence diagram', () => {
expect(svg).to.have.attr('width', '100%');
expect(svg).to.have.attr('height');
const height = parseFloat(svg.attr('height'));
expect(height).to.be.within(920, 960);
expect(height).to.be.within(920, 971);
const style = svg.attr('style');
expect(style).to.match(/^max-width: [\d.]+px;$/);
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
@@ -683,7 +733,7 @@ context('Sequence diagram', () => {
cy.get('svg').should((svg) => {
const height = parseFloat(svg.attr('height'));
const width = parseFloat(svg.attr('width'));
expect(height).to.be.within(920, 960);
expect(height).to.be.within(920, 971);
// use within because the absolute value can be slightly different depending on the environment ±5%
expect(width).to.be.within(820 * 0.95, 820 * 1.05);
expect(svg).to.not.have.attr('style');

View File

@@ -346,6 +346,21 @@ describe('State diagram', () => {
}
);
});
it('v2 A compound state should be able to link to itself', () => {
imgSnapshotTest(
`
stateDiagram
state Active {
Idle
}
Inactive --> Idle: ACT
Active --> Active: LOG
`,
{
logLevel: 0,
}
);
});
it('v2 width of compond state should grow with title if title is wider', () => {
imgSnapshotTest(
`

View File

@@ -36,6 +36,8 @@ describe('Pie Chart', () => {
imgSnapshotTest(
`
pie title Sports in Sweden
accTitle: This is a title
accDescr: This is a description
"Bandy" : 40
"Ice-Hockey" : 80
"Football" : 90
@@ -49,6 +51,8 @@ describe('Pie Chart', () => {
`
%%{init: { 'logLevel': 0} }%%
graph TD
accTitle: This is a title
accDescr: This is a description
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[/Another/]
@@ -72,6 +76,9 @@ describe('Pie Chart', () => {
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
flowchart TD
accTitle: This is a title
accDescr: This is a description
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
B --> G[Another]
@@ -95,6 +102,9 @@ describe('Pie Chart', () => {
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
sequenceDiagram
accTitle: This is a title
accDescr: This is a description
autonumber
par Action 1
Alice->>John: Hello John, how are you?
@@ -122,6 +132,9 @@ describe('Pie Chart', () => {
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
classDiagram
accTitle: This is a title
accDescr: This is a description
Animal "*" <|-- "1" Duck
Animal "1" <|-- "10" Fish
Animal <|-- Zebra
@@ -168,6 +181,9 @@ describe('Pie Chart', () => {
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
stateDiagram
accTitle: This is a title
accDescr: This is a description
[*] --> Active
state Active {
@@ -200,6 +216,9 @@ stateDiagram
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
stateDiagram-v2
accTitle: This is a title
accDescr: This is a description
[*] --> Active
state Active {
@@ -231,6 +250,9 @@ stateDiagram-v2
imgSnapshotTest(
`
erDiagram
accTitle: This is a title
accDescr: This is a description
CUSTOMER }|..|{ DELIVERY-ADDRESS : has
CUSTOMER ||--o{ ORDER : places
CUSTOMER ||--o{ INVOICE : "liable for"
@@ -250,6 +272,9 @@ erDiagram
`
%%{init: { 'logLevel': 0, 'theme': '${theme}'} }%%
journey
accTitle: This is a title
accDescr: This is a description
title My working day
section Go to work
Make tea: 5: Me
@@ -268,6 +293,9 @@ erDiagram
imgSnapshotTest(
`
gantt
accTitle: This is a title
accDescr: This is a description
dateFormat :YYYY-MM-DD
title :Adding GANTT diagram functionality to mermaid
excludes :excludes the named dates/days from being included in a charted task..

View File

@@ -1,264 +0,0 @@
/// <reference types="Cypress" />
context('Actions', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/actions');
});
// https://on.cypress.io/interacting-with-elements
it('.type() - type into a DOM element', () => {
// https://on.cypress.io/type
cy.get('.action-email')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
// .type() with special character sequences
.type('{leftarrow}{rightarrow}{uparrow}{downarrow}')
.type('{del}{selectall}{backspace}')
// .type() with key modifiers
.type('{alt}{option}') //these are equivalent
.type('{ctrl}{control}') //these are equivalent
.type('{meta}{command}{cmd}') //these are equivalent
.type('{shift}')
// Delay each keypress by 0.1 sec
.type('slow.typing@email.com', { delay: 100 })
.should('have.value', 'slow.typing@email.com');
cy.get('.action-disabled')
// Ignore error checking prior to type
// like whether the input is visible or disabled
.type('disabled error checking', { force: true })
.should('have.value', 'disabled error checking');
});
it('.focus() - focus on a DOM element', () => {
// https://on.cypress.io/focus
cy.get('.action-focus')
.focus()
.should('have.class', 'focus')
.prev()
.should('have.attr', 'style', 'color: orange;');
});
it('.blur() - blur off a DOM element', () => {
// https://on.cypress.io/blur
cy.get('.action-blur')
.type('About to blur')
.blur()
.should('have.class', 'error')
.prev()
.should('have.attr', 'style', 'color: red;');
});
it('.clear() - clears an input or textarea element', () => {
// https://on.cypress.io/clear
cy.get('.action-clear')
.type('Clear this text')
.should('have.value', 'Clear this text')
.clear()
.should('have.value', '');
});
it('.submit() - submit a form', () => {
// https://on.cypress.io/submit
cy.get('.action-form').find('[type="text"]').type('HALFOFF');
cy.get('.action-form').submit().next().should('contain', 'Your form has been submitted!');
});
it('.click() - click on a DOM element', () => {
// https://on.cypress.io/click
cy.get('.action-btn').click();
// You can click on 9 specific positions of an element:
// -----------------------------------
// | topLeft top topRight |
// | |
// | |
// | |
// | left center right |
// | |
// | |
// | |
// | bottomLeft bottom bottomRight |
// -----------------------------------
// clicking in the center of the element is the default
cy.get('#action-canvas').click();
cy.get('#action-canvas').click('topLeft');
cy.get('#action-canvas').click('top');
cy.get('#action-canvas').click('topRight');
cy.get('#action-canvas').click('left');
cy.get('#action-canvas').click('right');
cy.get('#action-canvas').click('bottomLeft');
cy.get('#action-canvas').click('bottom');
cy.get('#action-canvas').click('bottomRight');
// .click() accepts an x and y coordinate
// that controls where the click occurs :)
cy.get('#action-canvas')
.click(80, 75) // click 80px on x coord and 75px on y coord
.click(170, 75)
.click(80, 165)
.click(100, 185)
.click(125, 190)
.click(150, 185)
.click(170, 165);
// click multiple elements by passing multiple: true
cy.get('.action-labels>.label').click({ multiple: true });
// Ignore error checking prior to clicking
cy.get('.action-opacity>.btn').click({ force: true });
});
it('.dblclick() - double click on a DOM element', () => {
// https://on.cypress.io/dblclick
// Our app has a listener on 'dblclick' event in our 'scripts.js'
// that hides the div and shows an input on double click
cy.get('.action-div').dblclick().should('not.be.visible');
cy.get('.action-input-hidden').should('be.visible');
});
it('.check() - check a checkbox or radio element', () => {
// https://on.cypress.io/check
// By default, .check() will check all
// matching checkbox or radio elements in succession, one after another
cy.get('.action-checkboxes [type="checkbox"]').not('[disabled]').check().should('be.checked');
cy.get('.action-radios [type="radio"]').not('[disabled]').check().should('be.checked');
// .check() accepts a value argument
cy.get('.action-radios [type="radio"]').check('radio1').should('be.checked');
// .check() accepts an array of values
cy.get('.action-multiple-checkboxes [type="checkbox"]')
.check(['checkbox1', 'checkbox2'])
.should('be.checked');
// Ignore error checking prior to checking
cy.get('.action-checkboxes [disabled]').check({ force: true }).should('be.checked');
cy.get('.action-radios [type="radio"]').check('radio3', { force: true }).should('be.checked');
});
it('.uncheck() - uncheck a checkbox element', () => {
// https://on.cypress.io/uncheck
// By default, .uncheck() will uncheck all matching
// checkbox elements in succession, one after another
cy.get('.action-check [type="checkbox"]').not('[disabled]').uncheck().should('not.be.checked');
// .uncheck() accepts a value argument
cy.get('.action-check [type="checkbox"]')
.check('checkbox1')
.uncheck('checkbox1')
.should('not.be.checked');
// .uncheck() accepts an array of values
cy.get('.action-check [type="checkbox"]')
.check(['checkbox1', 'checkbox3'])
.uncheck(['checkbox1', 'checkbox3'])
.should('not.be.checked');
// Ignore error checking prior to unchecking
cy.get('.action-check [disabled]').uncheck({ force: true }).should('not.be.checked');
});
it('.select() - select an option in a <select> element', () => {
// https://on.cypress.io/select
// Select option(s) with matching text content
cy.get('.action-select').select('apples');
cy.get('.action-select-multiple').select(['apples', 'oranges', 'bananas']);
// Select option(s) with matching value
cy.get('.action-select').select('fr-bananas');
cy.get('.action-select-multiple').select(['fr-apples', 'fr-oranges', 'fr-bananas']);
});
it('.scrollIntoView() - scroll an element into view', () => {
// https://on.cypress.io/scrollintoview
// normally all of these buttons are hidden,
// because they're not within
// the viewable area of their parent
// (we need to scroll to see them)
cy.get('#scroll-horizontal button').should('not.be.visible');
// scroll the button into view, as if the user had scrolled
cy.get('#scroll-horizontal button').scrollIntoView().should('be.visible');
cy.get('#scroll-vertical button').should('not.be.visible');
// Cypress handles the scroll direction needed
cy.get('#scroll-vertical button').scrollIntoView().should('be.visible');
cy.get('#scroll-both button').should('not.be.visible');
// Cypress knows to scroll to the right and down
cy.get('#scroll-both button').scrollIntoView().should('be.visible');
});
it('.trigger() - trigger an event on a DOM element', () => {
// https://on.cypress.io/trigger
// To interact with a range input (slider)
// we need to set its value & trigger the
// event to signal it changed
// Here, we invoke jQuery's val() method to set
// the value and trigger the 'change' event
cy.get('.trigger-input-range')
.invoke('val', 25)
.trigger('change')
.get('input[type=range]')
.siblings('p')
.should('have.text', '25');
});
it('cy.scrollTo() - scroll the window or element to a position', () => {
// https://on.cypress.io/scrollTo
// You can scroll to 9 specific positions of an element:
// -----------------------------------
// | topLeft top topRight |
// | |
// | |
// | |
// | left center right |
// | |
// | |
// | |
// | bottomLeft bottom bottomRight |
// -----------------------------------
// if you chain .scrollTo() off of cy, we will
// scroll the entire window
cy.scrollTo('bottom');
cy.get('#scrollable-horizontal').scrollTo('right');
// or you can scroll to a specific coordinate:
// (x axis, y axis) in pixels
cy.get('#scrollable-vertical').scrollTo(250, 250);
// or you can scroll to a specific percentage
// of the (width, height) of the element
cy.get('#scrollable-both').scrollTo('75%', '25%');
// control the easing of the scroll (default is 'swing')
cy.get('#scrollable-vertical').scrollTo('center', { easing: 'linear' });
// control the duration of the scroll (in ms)
cy.get('#scrollable-both').scrollTo('center', { duration: 2000 });
});
});

View File

@@ -1,36 +0,0 @@
/// <reference types="Cypress" />
context('Aliasing', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/aliasing');
});
it('.as() - alias a DOM element for later use', () => {
// https://on.cypress.io/as
// Alias a DOM element for use later
// We don't have to traverse to the element
// later in our code, we reference it with @
cy.get('.as-table').find('tbody>tr').first().find('td').first().find('button').as('firstBtn');
// when we reference the alias, we place an
// @ in front of its name
cy.get('@firstBtn').click();
cy.get('@firstBtn').should('have.class', 'btn-success').and('contain', 'Changed');
});
it('.as() - alias a route for later use', () => {
// Alias the route to wait for its response
cy.server();
cy.route('GET', 'comments/*').as('getComment');
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.network-btn').click();
// https://on.cypress.io/wait
cy.wait('@getComment').its('status').should('eq', 200);
});
});

View File

@@ -1,169 +0,0 @@
/// <reference types="Cypress" />
context('Assertions', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/assertions');
});
describe('Implicit Assertions', () => {
it('.should() - make an assertion about the current subject', () => {
// https://on.cypress.io/should
cy.get('.assertion-table')
.find('tbody tr:last')
.should('have.class', 'success')
.find('td')
.first()
// checking the text of the <td> element in various ways
.should('have.text', 'Column content')
.should('contain', 'Column content')
.should('have.html', 'Column content')
// chai-jquery uses "is()" to check if element matches selector
.should('match', 'td')
// to match text content against a regular expression
// first need to invoke jQuery method text()
// and then match using regular expression
.invoke('text')
.should('match', /column content/i);
// a better way to check element's text content against a regular expression
// is to use "cy.contains"
// https://on.cypress.io/contains
cy.get('.assertion-table')
.find('tbody tr:last')
// finds first <td> element with text content matching regular expression
.contains('td', /column content/i)
.should('be.visible');
// for more information about asserting element's text
// see https://on.cypress.io/using-cypress-faq#How-do-I-get-an-elements-text-contents
});
it('.and() - chain multiple assertions together', () => {
// https://on.cypress.io/and
cy.get('.assertions-link')
.should('have.class', 'active')
.and('have.attr', 'href')
.and('include', 'cypress.io');
});
});
describe('Explicit Assertions', () => {
// https://on.cypress.io/assertions
it('expect - make an assertion about a specified subject', () => {
// We can use Chai's BDD style assertions
expect(true).to.be.true;
const o = { foo: 'bar' };
expect(o).to.equal(o);
expect(o).to.deep.equal({ foo: 'bar' });
// matching text using regular expression
expect('FooBar').to.match(/bar$/i);
});
it('pass your own callback function to should()', () => {
// Pass a function to should that can have any number
// of explicit assertions within it.
// The ".should(cb)" function will be retried
// automatically until it passes all your explicit assertions or times out.
cy.get('.assertions-p')
.find('p')
.should(($p) => {
// https://on.cypress.io/$
// return an array of texts from all of the p's
// @ts-ignore TS6133 unused variable
const texts = $p.map((i, el) => Cypress.$(el).text());
// jquery map returns jquery object
// and .get() convert this to simple array
const paragraphs = texts.get();
// array should have length of 3
expect(paragraphs, 'has 3 paragraphs').to.have.length(3);
// use second argument to expect(...) to provide clear
// message with each assertion
expect(paragraphs, 'has expected text in each paragraph').to.deep.eq([
'Some text from first p',
'More text from second p',
'And even more text from third p',
]);
});
});
it('finds element by class name regex', () => {
cy.get('.docs-header')
.find('div')
// .should(cb) callback function will be retried
.should(($div) => {
expect($div).to.have.length(1);
const className = $div[0].className;
expect(className).to.match(/heading-/);
})
// .then(cb) callback is not retried,
// it either passes or fails
.then(($div) => {
expect($div, 'text content').to.have.text('Introduction');
});
});
it('can throw any error', () => {
cy.get('.docs-header')
.find('div')
.should(($div) => {
if ($div.length !== 1) {
// you can throw your own errors
throw new Error('Did not find 1 element');
}
const className = $div[0].className;
if (!className.match(/heading-/)) {
throw new Error(`Could not find class "heading-" in ${className}`);
}
});
});
it('matches unknown text between two elements', () => {
/**
* Text from the first element.
*
* @type {string}
*/
let text;
/**
* Normalizes passed text, useful before comparing text with spaces and different capitalization.
*
* @param {string} s Text to normalize
*/
const normalizeText = (s) => s.replace(/\s/g, '').toLowerCase();
cy.get('.two-elements')
.find('.first')
.then(($first) => {
// save text from the first element
text = normalizeText($first.text());
});
cy.get('.two-elements')
.find('.second')
.should(($div) => {
// we can massage text before comparing
const secondText = normalizeText($div.text());
expect(secondText, 'second text').to.equal(text);
});
});
it('assert - assert shape of an object', () => {
const person = {
name: 'Joe',
age: 20,
};
assert.isObject(person, 'value is object');
});
});
});

View File

@@ -1,55 +0,0 @@
/// <reference types="Cypress" />
context('Connectors', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/connectors');
});
it('.each() - iterate over an array of elements', () => {
// https://on.cypress.io/each
cy.get('.connectors-each-ul>li').each(($el, index, $list) => {
console.log($el, index, $list);
});
});
it('.its() - get properties on the current subject', () => {
// https://on.cypress.io/its
cy.get('.connectors-its-ul>li')
// calls the 'length' property yielding that value
.its('length')
.should('be.gt', 2);
});
it('.invoke() - invoke a function on the current subject', () => {
// our div is hidden in our script.js
// $('.connectors-div').hide()
// https://on.cypress.io/invoke
cy.get('.connectors-div')
.should('be.hidden')
// call the jquery method 'show' on the 'div.container'
.invoke('show')
.should('be.visible');
});
it('.spread() - spread an array as individual args to callback function', () => {
// https://on.cypress.io/spread
const arr = ['foo', 'bar', 'baz'];
cy.wrap(arr).spread((foo, bar, baz) => {
expect(foo).to.eq('foo');
expect(bar).to.eq('bar');
expect(baz).to.eq('baz');
});
});
it('.then() - invoke a callback function with the current subject', () => {
// https://on.cypress.io/then
cy.get('.connectors-list > li').then(($lis) => {
expect($lis, '3 items').to.have.length(3);
expect($lis.eq(0), 'first item').to.contain('Walk the dog');
expect($lis.eq(1), 'second item').to.contain('Feed the cat');
expect($lis.eq(2), 'third item').to.contain('Write JavaScript');
});
});
});

View File

@@ -1,79 +0,0 @@
/// <reference types="Cypress" />
context('Cookies', () => {
beforeEach(() => {
Cypress.Cookies.debug(true);
cy.visit('https://example.cypress.io/commands/cookies');
// clear cookies again after visiting to remove
// any 3rd party cookies picked up such as cloudflare
cy.clearCookies();
});
it('cy.getCookie() - get a browser cookie', () => {
// https://on.cypress.io/getcookie
cy.get('#getCookie .set-a-cookie').click();
// cy.getCookie() yields a cookie object
cy.getCookie('token').should('have.property', 'value', '123ABC');
});
it('cy.getCookies() - get browser cookies', () => {
// https://on.cypress.io/getcookies
cy.getCookies().should('be.empty');
cy.get('#getCookies .set-a-cookie').click();
// cy.getCookies() yields an array of cookies
cy.getCookies()
.should('have.length', 1)
.should((cookies) => {
// each cookie has these properties
expect(cookies[0]).to.have.property('name', 'token');
expect(cookies[0]).to.have.property('value', '123ABC');
expect(cookies[0]).to.have.property('httpOnly', false);
expect(cookies[0]).to.have.property('secure', false);
expect(cookies[0]).to.have.property('domain');
expect(cookies[0]).to.have.property('path');
});
});
it('cy.setCookie() - set a browser cookie', () => {
// https://on.cypress.io/setcookie
cy.getCookies().should('be.empty');
cy.setCookie('foo', 'bar');
// cy.getCookie() yields a cookie object
cy.getCookie('foo').should('have.property', 'value', 'bar');
});
it('cy.clearCookie() - clear a browser cookie', () => {
// https://on.cypress.io/clearcookie
cy.getCookie('token').should('be.null');
cy.get('#clearCookie .set-a-cookie').click();
cy.getCookie('token').should('have.property', 'value', '123ABC');
// cy.clearCookies() yields null
cy.clearCookie('token').should('be.null');
cy.getCookie('token').should('be.null');
});
it('cy.clearCookies() - clear browser cookies', () => {
// https://on.cypress.io/clearcookies
cy.getCookies().should('be.empty');
cy.get('#clearCookies .set-a-cookie').click();
cy.getCookies().should('have.length', 1);
// cy.clearCookies() yields null
cy.clearCookies();
cy.getCookies().should('be.empty');
});
});

View File

@@ -1,225 +0,0 @@
/// <reference types="Cypress" />
context('Cypress.Commands', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api');
});
// https://on.cypress.io/custom-commands
it('.add() - create a custom command', () => {
Cypress.Commands.add(
'console',
{
prevSubject: true,
},
(subject, method) => {
// the previous subject is automatically received
// and the commands arguments are shifted
// allow us to change the console method used
method = method || 'log';
// log the subject to the console
// @ts-ignore TS7017
console[method]('The subject is', subject);
// whatever we return becomes the new subject
// we don't want to change the subject so
// we return whatever was passed in
return subject;
}
);
// @ts-ignore TS2339
cy.get('button')
.console('info')
.then(($button) => {
// subject is still $button
});
});
});
context('Cypress.Cookies', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api');
});
// https://on.cypress.io/cookies
it('.debug() - enable or disable debugging', () => {
Cypress.Cookies.debug(true);
// Cypress will now log in the console when
// cookies are set or cleared
cy.setCookie('fakeCookie', '123ABC');
cy.clearCookie('fakeCookie');
cy.setCookie('fakeCookie', '123ABC');
cy.clearCookie('fakeCookie');
cy.setCookie('fakeCookie', '123ABC');
});
it('.preserveOnce() - preserve cookies by key', () => {
// normally cookies are reset after each test
cy.getCookie('fakeCookie').should('not.be.ok');
// preserving a cookie will not clear it when
// the next test starts
cy.setCookie('lastCookie', '789XYZ');
Cypress.Cookies.preserveOnce('lastCookie');
});
it('.defaults() - set defaults for all cookies', () => {
// now any cookie with the name 'session_id' will
// not be cleared before each new test runs
Cypress.Cookies.defaults({
whitelist: 'session_id',
});
});
});
context('Cypress.Server', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api');
});
// Permanently override server options for
// all instances of cy.server()
// https://on.cypress.io/cypress-server
it('.defaults() - change default config of server', () => {
Cypress.Server.defaults({
delay: 0,
force404: false,
});
});
});
context('Cypress.arch', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api');
});
it('Get CPU architecture name of underlying OS', () => {
// https://on.cypress.io/arch
expect(Cypress.arch).to.exist;
});
});
context('Cypress.config()', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api');
});
it('Get and set configuration options', () => {
// https://on.cypress.io/config
let myConfig = Cypress.config();
expect(myConfig).to.have.property('animationDistanceThreshold', 5);
expect(myConfig).to.have.property('baseUrl', null);
expect(myConfig).to.have.property('defaultCommandTimeout', 4000);
expect(myConfig).to.have.property('requestTimeout', 5000);
expect(myConfig).to.have.property('responseTimeout', 30000);
expect(myConfig).to.have.property('viewportHeight', 660);
expect(myConfig).to.have.property('viewportWidth', 1000);
expect(myConfig).to.have.property('pageLoadTimeout', 60000);
expect(myConfig).to.have.property('waitForAnimations', true);
expect(Cypress.config('pageLoadTimeout')).to.eq(60000);
// this will change the config for the rest of your tests!
Cypress.config('pageLoadTimeout', 20000);
expect(Cypress.config('pageLoadTimeout')).to.eq(20000);
Cypress.config('pageLoadTimeout', 60000);
});
});
context('Cypress.dom', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api');
});
// https://on.cypress.io/dom
it('.isHidden() - determine if a DOM element is hidden', () => {
let hiddenP = Cypress.$('.dom-p p.hidden').get(0);
let visibleP = Cypress.$('.dom-p p.visible').get(0);
// our first paragraph has css class 'hidden'
expect(Cypress.dom.isHidden(hiddenP)).to.be.true;
expect(Cypress.dom.isHidden(visibleP)).to.be.false;
});
});
context('Cypress.env()', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api');
});
// We can set environment variables for highly dynamic values
// https://on.cypress.io/environment-variables
it('Get environment variables', () => {
// https://on.cypress.io/env
// set multiple environment variables
Cypress.env({
host: 'veronica.dev.local',
api_server: 'http://localhost:8888/v1/',
});
// get environment variable
expect(Cypress.env('host')).to.eq('veronica.dev.local');
// set environment variable
Cypress.env('api_server', 'http://localhost:8888/v2/');
expect(Cypress.env('api_server')).to.eq('http://localhost:8888/v2/');
// get all environment variable
expect(Cypress.env()).to.have.property('host', 'veronica.dev.local');
expect(Cypress.env()).to.have.property('api_server', 'http://localhost:8888/v2/');
});
});
context('Cypress.log', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api');
});
it('Control what is printed to the Command Log', () => {
// https://on.cypress.io/cypress-log
});
});
context('Cypress.platform', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api');
});
it('Get underlying OS name', () => {
// https://on.cypress.io/platform
expect(Cypress.platform).to.be.exist;
});
});
context('Cypress.version', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api');
});
it('Get current version of Cypress being run', () => {
// https://on.cypress.io/version
expect(Cypress.version).to.be.exist;
});
});
context('Cypress.spec', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api');
});
it('Get current spec information', () => {
// https://on.cypress.io/spec
// wrap the object so we can inspect it easily by clicking in the command log
cy.wrap(Cypress.spec).should('have.keys', ['name', 'relative', 'absolute']);
});
});

View File

@@ -1,114 +0,0 @@
/// <reference types="Cypress" />
/// JSON fixture file can be loaded directly using
// the built-in JavaScript bundler
// @ts-ignore
const requiredExample = require('../../fixtures/example');
context('Files', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/files');
});
beforeEach(() => {
// load example.json fixture file and store
// in the test context object
cy.fixture('example.json').as('example');
});
it('cy.fixture() - load a fixture', () => {
// https://on.cypress.io/fixture
// Instead of writing a response inline you can
// use a fixture file's content.
cy.server();
cy.fixture('example.json').as('comment');
// when application makes an Ajax request matching "GET comments/*"
// Cypress will intercept it and reply with object
// from the "comment" alias
cy.route('GET', 'comments/*', '@comment').as('getComment');
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.fixture-btn').click();
cy.wait('@getComment')
.its('responseBody')
.should('have.property', 'name')
.and('include', 'Using fixtures to represent data');
// you can also just write the fixture in the route
cy.route('GET', 'comments/*', 'fixture:example.json').as('getComment');
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.fixture-btn').click();
cy.wait('@getComment')
.its('responseBody')
.should('have.property', 'name')
.and('include', 'Using fixtures to represent data');
// or write fx to represent fixture
// by default it assumes it's .json
cy.route('GET', 'comments/*', 'fx:example').as('getComment');
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.fixture-btn').click();
cy.wait('@getComment')
.its('responseBody')
.should('have.property', 'name')
.and('include', 'Using fixtures to represent data');
});
it('cy.fixture() or require - load a fixture', function () {
// we are inside the "function () { ... }"
// callback and can use test context object "this"
// "this.example" was loaded in "beforeEach" function callback
expect(this.example, 'fixture in the test context').to.deep.equal(requiredExample);
// or use "cy.wrap" and "should('deep.equal', ...)" assertion
// @ts-ignore
cy.wrap(this.example, 'fixture vs require').should('deep.equal', requiredExample);
});
it('cy.readFile() - read a files contents', () => {
// https://on.cypress.io/readfile
// You can read a file and yield its contents
// The filePath is relative to your project's root.
cy.readFile('cypress.json').then((json) => {
expect(json).to.be.an('object');
});
});
it('cy.writeFile() - write to a file', () => {
// https://on.cypress.io/writefile
// You can write to a file
// Use a response from a request to automatically
// generate a fixture file for use later
cy.request('https://jsonplaceholder.cypress.io/users').then((response) => {
cy.writeFile('cypress/fixtures/users.json', response.body);
});
cy.fixture('users').should((users) => {
expect(users[0].name).to.exist;
});
// JavaScript arrays and objects are stringified
// and formatted into text.
cy.writeFile('cypress/fixtures/profile.json', {
id: 8739,
name: 'Jane',
email: 'jane@example.com',
});
cy.fixture('profile').should((profile) => {
expect(profile.name).to.eq('Jane');
});
});
});

View File

@@ -1,58 +0,0 @@
/// <reference types="Cypress" />
context('Local Storage', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/local-storage');
});
// Although local storage is automatically cleared
// in between tests to maintain a clean state
// sometimes we need to clear the local storage manually
it('cy.clearLocalStorage() - clear all data in local storage', () => {
// https://on.cypress.io/clearlocalstorage
cy.get('.ls-btn')
.click()
.should(() => {
expect(localStorage.getItem('prop1')).to.eq('red');
expect(localStorage.getItem('prop2')).to.eq('blue');
expect(localStorage.getItem('prop3')).to.eq('magenta');
});
// clearLocalStorage() yields the localStorage object
cy.clearLocalStorage().should((ls) => {
expect(ls.getItem('prop1')).to.be.null;
expect(ls.getItem('prop2')).to.be.null;
expect(ls.getItem('prop3')).to.be.null;
});
// Clear key matching string in Local Storage
cy.get('.ls-btn')
.click()
.should(() => {
expect(localStorage.getItem('prop1')).to.eq('red');
expect(localStorage.getItem('prop2')).to.eq('blue');
expect(localStorage.getItem('prop3')).to.eq('magenta');
});
cy.clearLocalStorage('prop1').should((ls) => {
expect(ls.getItem('prop1')).to.be.null;
expect(ls.getItem('prop2')).to.eq('blue');
expect(ls.getItem('prop3')).to.eq('magenta');
});
// Clear keys matching regex in Local Storage
cy.get('.ls-btn')
.click()
.should(() => {
expect(localStorage.getItem('prop1')).to.eq('red');
expect(localStorage.getItem('prop2')).to.eq('blue');
expect(localStorage.getItem('prop3')).to.eq('magenta');
});
cy.clearLocalStorage(/prop1|2/).should((ls) => {
expect(ls.getItem('prop1')).to.be.null;
expect(ls.getItem('prop2')).to.be.null;
expect(ls.getItem('prop3')).to.eq('magenta');
});
});
});

View File

@@ -1,32 +0,0 @@
/// <reference types="Cypress" />
context('Location', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/location');
});
it('cy.hash() - get the current URL hash', () => {
// https://on.cypress.io/hash
cy.hash().should('be.empty');
});
it('cy.location() - get window.location', () => {
// https://on.cypress.io/location
cy.location().should((location) => {
expect(location.hash).to.be.empty;
expect(location.href).to.eq('https://example.cypress.io/commands/location');
expect(location.host).to.eq('example.cypress.io');
expect(location.hostname).to.eq('example.cypress.io');
expect(location.origin).to.eq('https://example.cypress.io');
expect(location.pathname).to.eq('/commands/location');
expect(location.port).to.eq('');
expect(location.protocol).to.eq('https:');
expect(location.search).to.be.empty;
});
});
it('cy.url() - get the current URL', () => {
// https://on.cypress.io/url
cy.url().should('eq', 'https://example.cypress.io/commands/location');
});
});

View File

@@ -1,77 +0,0 @@
/// <reference types="Cypress" />
context('Misc', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/misc');
});
it('.end() - end the command chain', () => {
// https://on.cypress.io/end
// cy.end is useful when you want to end a chain of commands
// and force Cypress to re-query from the root element
cy.get('.misc-table').within(() => {
// ends the current chain and yields null
cy.contains('Cheryl').click().end();
// queries the entire table again
cy.contains('Charles').click();
});
});
it('cy.exec() - execute a system command', () => {
// https://on.cypress.io/exec
// execute a system command.
// so you can take actions necessary for
// your test outside the scope of Cypress.
cy.exec('echo Jane Lane').its('stdout').should('contain', 'Jane Lane');
// we can use Cypress.platform string to
// select appropriate command
// https://on.cypress/io/platform
cy.log(`Platform ${Cypress.platform} architecture ${Cypress.arch}`);
if (Cypress.platform === 'win32') {
cy.exec('print cypress.json').its('stderr').should('be.empty');
} else {
cy.exec('cat cypress.json').its('stderr').should('be.empty');
cy.exec('pwd').its('code').should('eq', 0);
}
});
it('cy.focused() - get the DOM element that has focus', () => {
// https://on.cypress.io/focused
cy.get('.misc-form').find('#name').click();
cy.focused().should('have.id', 'name');
cy.get('.misc-form').find('#description').click();
cy.focused().should('have.id', 'description');
});
context('Cypress.Screenshot', function () {
it('cy.screenshot() - take a screenshot', () => {
// https://on.cypress.io/screenshot
cy.screenshot('my-image');
});
it('Cypress.Screenshot.defaults() - change default config of screenshots', function () {
Cypress.Screenshot.defaults({
blackout: ['.foo'],
capture: 'viewport',
clip: { x: 0, y: 0, width: 200, height: 200 },
scale: false,
disableTimersAndAnimations: true,
screenshotOnRunFailure: true,
beforeScreenshot() {},
afterScreenshot() {},
});
});
});
it('cy.wrap() - wrap an object', () => {
// https://on.cypress.io/wrap
cy.wrap({ foo: 'bar' }).should('have.property', 'foo').and('include', 'bar');
});
});

View File

@@ -1,56 +0,0 @@
/// <reference types="Cypress" />
context('Navigation', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io');
cy.get('.navbar-nav').contains('Commands').click();
cy.get('.dropdown-menu').contains('Navigation').click();
});
it("cy.go() - go back or forward in the browser's history", () => {
// https://on.cypress.io/go
cy.location('pathname').should('include', 'navigation');
cy.go('back');
cy.location('pathname').should('not.include', 'navigation');
cy.go('forward');
cy.location('pathname').should('include', 'navigation');
// clicking back
cy.go(-1);
cy.location('pathname').should('not.include', 'navigation');
// clicking forward
cy.go(1);
cy.location('pathname').should('include', 'navigation');
});
it('cy.reload() - reload the page', () => {
// https://on.cypress.io/reload
cy.reload();
// reload the page without using the cache
cy.reload(true);
});
it('cy.visit() - visit a remote url', () => {
// https://on.cypress.io/visit
// Visit any sub-domain of your current domain
// Pass options to the visit
cy.visit('https://example.cypress.io/commands/navigation', {
timeout: 50000, // increase total time for the visit to resolve
onBeforeLoad(contentWindow) {
// contentWindow is the remote page's window object
expect(typeof contentWindow === 'object').to.be.true;
},
onLoad(contentWindow) {
// contentWindow is the remote page's window object
expect(typeof contentWindow === 'object').to.be.true;
},
});
});
});

View File

@@ -1,192 +0,0 @@
/// <reference types="Cypress" />
context('Network Requests', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/network-requests');
});
// Manage AJAX / XHR requests in your app
it('cy.server() - control behavior of network requests and responses', () => {
// https://on.cypress.io/server
cy.server().should((server) => {
// the default options on server
// you can override any of these options
expect(server.delay).to.eq(0);
expect(server.method).to.eq('GET');
expect(server.status).to.eq(200);
expect(server.headers).to.be.null;
expect(server.response).to.be.null;
expect(server.onRequest).to.be.undefined;
expect(server.onResponse).to.be.undefined;
expect(server.onAbort).to.be.undefined;
// These options control the server behavior
// affecting all requests
// pass false to disable existing route stubs
expect(server.enable).to.be.true;
// forces requests that don't match your routes to 404
expect(server.force404).to.be.false;
// whitelists requests from ever being logged or stubbed
expect(server.whitelist).to.be.a('function');
});
cy.server({
method: 'POST',
delay: 1000,
status: 422,
response: {},
});
// any route commands will now inherit the above options
// from the server. anything we pass specifically
// to route will override the defaults though.
});
it('cy.request() - make an XHR request', () => {
// https://on.cypress.io/request
cy.request('https://jsonplaceholder.cypress.io/comments').should((response) => {
expect(response.status).to.eq(200);
expect(response.body).to.have.length(500);
expect(response).to.have.property('headers');
expect(response).to.have.property('duration');
});
});
it('cy.request() - verify response using BDD syntax', () => {
cy.request('https://jsonplaceholder.cypress.io/comments').then((response) => {
// https://on.cypress.io/assertions
expect(response).property('status').to.equal(200);
expect(response).property('body').to.have.length(500);
expect(response).to.include.keys('headers', 'duration');
});
});
it('cy.request() with query parameters', () => {
// will execute request
// https://jsonplaceholder.cypress.io/comments?postId=1&id=3
cy.request({
url: 'https://jsonplaceholder.cypress.io/comments',
qs: {
postId: 1,
id: 3,
},
})
.its('body')
.should('be.an', 'array')
.and('have.length', 1)
.its('0') // yields first element of the array
.should('contain', {
postId: 1,
id: 3,
});
});
it('cy.request() - pass result to the second request', () => {
// first, let's find out the userId of the first user we have
cy.request('https://jsonplaceholder.cypress.io/users?_limit=1')
.its('body.0') // yields the first element of the returned list
.then((user) => {
expect(user).property('id').to.be.a('number');
// make a new post on behalf of the user
cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', {
userId: user.id,
title: 'Cypress Test Runner',
body: 'Fast, easy and reliable testing for anything that runs in a browser.',
});
})
// note that the value here is the returned value of the 2nd request
// which is the new post object
.then((response) => {
expect(response).property('status').to.equal(201); // new entity created
expect(response).property('body').to.contain({
id: 101, // there are already 100 posts, so new entity gets id 101
title: 'Cypress Test Runner',
});
// we don't know the user id here - since it was in above closure
// so in this test just confirm that the property is there
expect(response.body).property('userId').to.be.a('number');
});
});
it('cy.request() - save response in the shared test context', () => {
// https://on.cypress.io/variables-and-aliases
cy.request('https://jsonplaceholder.cypress.io/users?_limit=1')
.its('body.0') // yields the first element of the returned list
.as('user') // saves the object in the test context
.then(function () {
// NOTE 👀
// By the time this callback runs the "as('user')" command
// has saved the user object in the test context.
// To access the test context we need to use
// the "function () { ... }" callback form,
// otherwise "this" points at a wrong or undefined object!
cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', {
userId: this.user.id,
title: 'Cypress Test Runner',
body: 'Fast, easy and reliable testing for anything that runs in a browser.',
})
.its('body')
.as('post'); // save the new post from the response
})
.then(function () {
// When this callback runs, both "cy.request" API commands have finished
// and the test context has "user" and "post" objects set.
// Let's verify them.
expect(this.post, 'post has the right user id').property('userId').to.equal(this.user.id);
});
});
it('cy.route() - route responses to matching requests', () => {
// https://on.cypress.io/route
let message = 'whoa, this comment does not exist';
cy.server();
// Listen to GET to comments/1
cy.route('GET', 'comments/*').as('getComment');
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.network-btn').click();
// https://on.cypress.io/wait
cy.wait('@getComment').its('status').should('eq', 200);
// Listen to POST to comments
cy.route('POST', '/comments').as('postComment');
// we have code that posts a comment when
// the button is clicked in scripts.js
cy.get('.network-post').click();
cy.wait('@postComment');
// get the route
cy.get('@postComment').should((xhr) => {
expect(xhr.requestBody).to.include('email');
expect(xhr.requestHeaders).to.have.property('Content-Type');
expect(xhr.responseBody).to.have.property('name', 'Using POST in cy.route()');
});
// Stub a response to PUT comments/ ****
cy.route({
method: 'PUT',
url: 'comments/*',
status: 404,
response: { error: message },
delay: 500,
}).as('putComment');
// we have code that puts a comment when
// the button is clicked in scripts.js
cy.get('.network-put').click();
cy.wait('@putComment');
// our 404 statusCode logic in scripts.js executed
cy.get('.network-put-comment').should('contain', message);
});
});

View File

@@ -1,75 +0,0 @@
/// <reference types="Cypress" />
context('Querying', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/querying');
});
// The most commonly used query is 'cy.get()', you can
// think of this like the '$' in jQuery
it('cy.get() - query DOM elements', () => {
// https://on.cypress.io/get
cy.get('#query-btn').should('contain', 'Button');
cy.get('.query-btn').should('contain', 'Button');
cy.get('#querying .well>button:first').should('contain', 'Button');
// ↲
// Use CSS selectors just like jQuery
cy.get('[data-test-id="test-example"]').should('have.class', 'example');
// 'cy.get()' yields jQuery object, you can get its attribute
// by invoking `.attr()` method
cy.get('[data-test-id="test-example"]')
.invoke('attr', 'data-test-id')
.should('equal', 'test-example');
// or you can get element's CSS property
cy.get('[data-test-id="test-example"]').invoke('css', 'position').should('equal', 'static');
// or use assertions directly during 'cy.get()'
// https://on.cypress.io/assertions
cy.get('[data-test-id="test-example"]')
.should('have.attr', 'data-test-id', 'test-example')
.and('have.css', 'position', 'static');
});
it('cy.contains() - query DOM elements with matching content', () => {
// https://on.cypress.io/contains
cy.get('.query-list').contains('bananas').should('have.class', 'third');
// we can pass a regexp to `.contains()`
cy.get('.query-list').contains(/^b\w+/).should('have.class', 'third');
cy.get('.query-list').contains('apples').should('have.class', 'first');
// passing a selector to contains will
// yield the selector containing the text
cy.get('#querying').contains('ul', 'oranges').should('have.class', 'query-list');
cy.get('.query-button').contains('Save Form').should('have.class', 'btn');
});
it('.within() - query DOM elements within a specific element', () => {
// https://on.cypress.io/within
cy.get('.query-form').within(() => {
cy.get('input:first').should('have.attr', 'placeholder', 'Email');
cy.get('input:last').should('have.attr', 'placeholder', 'Password');
});
});
it('cy.root() - query the root DOM element', () => {
// https://on.cypress.io/root
// By default, root is the document
cy.root().should('match', 'html');
cy.get('.query-ul').within(() => {
// In this within, the root is now the ul DOM element
cy.root().should('have.class', 'query-ul');
});
});
});

View File

@@ -1,94 +0,0 @@
/// <reference types="Cypress" />
context('Spies, Stubs, and Clock', () => {
it('cy.spy() - wrap a method in a spy', () => {
// https://on.cypress.io/spy
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks');
const obj = {
foo() {},
};
const spy = cy.spy(obj, 'foo').as('anyArgs');
obj.foo();
expect(spy).to.be.called;
});
it('cy.spy() retries until assertions pass', () => {
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks');
const obj = {
/**
* Prints the argument passed
*
* @param x {any}
*/
foo(x) {
console.log('obj.foo called with', x);
},
};
cy.spy(obj, 'foo').as('foo');
setTimeout(() => {
obj.foo('first');
}, 500);
setTimeout(() => {
obj.foo('second');
}, 2500);
cy.get('@foo').should('have.been.calledTwice');
});
it('cy.stub() - create a stub and/or replace a function with stub', () => {
// https://on.cypress.io/stub
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks');
const obj = {
/**
* Prints both arguments to the console
*
* @param a {string}
* @param b {string}
*/
foo(a, b) {
console.log('a', a, 'b', b);
},
};
const stub = cy.stub(obj, 'foo').as('foo');
obj.foo('foo', 'bar');
expect(stub).to.be.called;
});
it('cy.clock() - control time in the browser', () => {
// https://on.cypress.io/clock
// create the date in UTC so its always the same
// no matter what local timezone the browser is running in
const now = new Date(Date.UTC(2017, 2, 14)).getTime();
cy.clock(now);
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks');
cy.get('#clock-div').click().should('have.text', '1489449600');
});
it('cy.tick() - move time in the browser', () => {
// https://on.cypress.io/tick
// create the date in UTC so its always the same
// no matter what local timezone the browser is running in
const now = new Date(Date.UTC(2017, 2, 14)).getTime();
cy.clock(now);
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks');
cy.get('#tick-div').click().should('have.text', '1489449600');
cy.tick(10000); // 10 seconds passed
cy.get('#tick-div').click().should('have.text', '1489449610');
});
});

View File

@@ -1,97 +0,0 @@
/// <reference types="Cypress" />
context('Traversal', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/traversal');
});
it('.children() - get child DOM elements', () => {
// https://on.cypress.io/children
cy.get('.traversal-breadcrumb').children('.active').should('contain', 'Data');
});
it('.closest() - get closest ancestor DOM element', () => {
// https://on.cypress.io/closest
cy.get('.traversal-badge').closest('ul').should('have.class', 'list-group');
});
it('.eq() - get a DOM element at a specific index', () => {
// https://on.cypress.io/eq
cy.get('.traversal-list>li').eq(1).should('contain', 'siamese');
});
it('.filter() - get DOM elements that match the selector', () => {
// https://on.cypress.io/filter
cy.get('.traversal-nav>li').filter('.active').should('contain', 'About');
});
it('.find() - get descendant DOM elements of the selector', () => {
// https://on.cypress.io/find
cy.get('.traversal-pagination').find('li').find('a').should('have.length', 7);
});
it('.first() - get first DOM element', () => {
// https://on.cypress.io/first
cy.get('.traversal-table td').first().should('contain', '1');
});
it('.last() - get last DOM element', () => {
// https://on.cypress.io/last
cy.get('.traversal-buttons .btn').last().should('contain', 'Submit');
});
it('.next() - get next sibling DOM element', () => {
// https://on.cypress.io/next
cy.get('.traversal-ul').contains('apples').next().should('contain', 'oranges');
});
it('.nextAll() - get all next sibling DOM elements', () => {
// https://on.cypress.io/nextall
cy.get('.traversal-next-all').contains('oranges').nextAll().should('have.length', 3);
});
it('.nextUntil() - get next sibling DOM elements until next el', () => {
// https://on.cypress.io/nextuntil
cy.get('#veggies').nextUntil('#nuts').should('have.length', 3);
});
it('.not() - remove DOM elements from set of DOM elements', () => {
// https://on.cypress.io/not
cy.get('.traversal-disabled .btn').not('[disabled]').should('not.contain', 'Disabled');
});
it('.parent() - get parent DOM element from DOM elements', () => {
// https://on.cypress.io/parent
cy.get('.traversal-mark').parent().should('contain', 'Morbi leo risus');
});
it('.parents() - get parent DOM elements from DOM elements', () => {
// https://on.cypress.io/parents
cy.get('.traversal-cite').parents().should('match', 'blockquote');
});
it('.parentsUntil() - get parent DOM elements from DOM elements until el', () => {
// https://on.cypress.io/parentsuntil
cy.get('.clothes-nav').find('.active').parentsUntil('.clothes-nav').should('have.length', 2);
});
it('.prev() - get previous sibling DOM element', () => {
// https://on.cypress.io/prev
cy.get('.birds').find('.active').prev().should('contain', 'Lorikeets');
});
it('.prevAll() - get all previous sibling DOM elements', () => {
// https://on.cypress.io/prevAll
cy.get('.fruits-list').find('.third').prevAll().should('have.length', 2);
});
it('.prevUntil() - get all previous sibling DOM elements until el', () => {
// https://on.cypress.io/prevUntil
cy.get('.foods-list').find('#nuts').prevUntil('#veggies').should('have.length', 3);
});
it('.siblings() - get all sibling DOM elements', () => {
// https://on.cypress.io/siblings
cy.get('.traversal-pills .active').siblings().should('have.length', 2);
});
});

View File

@@ -1,129 +0,0 @@
/// <reference types="Cypress" />
context('Utilities', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/utilities');
});
it('Cypress._ - call a lodash method', () => {
// https://on.cypress.io/_
cy.request('https://jsonplaceholder.cypress.io/users').then((response) => {
let ids = Cypress._.chain(response.body).map('id').take(3).value();
expect(ids).to.deep.eq([1, 2, 3]);
});
});
it('Cypress.$ - call a jQuery method', () => {
// https://on.cypress.io/$
let $li = Cypress.$('.utility-jquery li:first');
cy.wrap($li).should('not.have.class', 'active').click().should('have.class', 'active');
});
it('Cypress.Blob - blob utilities and base64 string conversion', () => {
// https://on.cypress.io/blob
cy.get('.utility-blob').then(($div) =>
// https://github.com/nolanlawson/blob-util#imgSrcToDataURL
// get the dataUrl string for the javascript-logo
Cypress.Blob.imgSrcToDataURL(
'https://example.cypress.io/assets/img/javascript-logo.png',
undefined,
'anonymous'
).then((dataUrl) => {
// create an <img> element and set its src to the dataUrl
let img = Cypress.$('<img />', { src: dataUrl });
// need to explicitly return cy here since we are initially returning
// the Cypress.Blob.imgSrcToDataURL promise to our test
// append the image
$div.append(img);
cy.get('.utility-blob img').click().should('have.attr', 'src', dataUrl);
})
);
});
it('Cypress.minimatch - test out glob patterns against strings', () => {
// https://on.cypress.io/minimatch
let matching = Cypress.minimatch('/users/1/comments', '/users/*/comments', {
matchBase: true,
});
expect(matching, 'matching wildcard').to.be.true;
matching = Cypress.minimatch('/users/1/comments/2', '/users/*/comments', {
matchBase: true,
});
expect(matching, 'comments').to.be.false;
// ** matches against all downstream path segments
matching = Cypress.minimatch('/foo/bar/baz/123/quux?a=b&c=2', '/foo/**', {
matchBase: true,
});
expect(matching, 'comments').to.be.true;
// whereas * matches only the next path segment
matching = Cypress.minimatch('/foo/bar/baz/123/quux?a=b&c=2', '/foo/*', {
matchBase: false,
});
expect(matching, 'comments').to.be.false;
});
it('Cypress.moment() - format or parse dates using a moment method', () => {
// https://on.cypress.io/moment
const time = Cypress.moment().utc('2014-04-25T19:38:53.196Z').format('h:mm A');
expect(time).to.be.a('string');
cy.get('.utility-moment').contains('3:38 PM').should('have.class', 'badge');
// the time in the element should be between 3pm and 5pm
const start = Cypress.moment('3:00 PM', 'LT');
const end = Cypress.moment('5:00 PM', 'LT');
cy.get('.utility-moment .badge').should(($el) => {
// parse American time like "3:38 PM"
const m = Cypress.moment($el.text().trim(), 'LT');
// display hours + minutes + AM|PM
const f = 'h:mm A';
expect(
m.isBetween(start, end),
`${m.format(f)} should be between ${start.format(f)} and ${end.format(f)}`
).to.be.true;
});
});
it('Cypress.Promise - instantiate a bluebird promise', () => {
// https://on.cypress.io/promise
let waited = false;
/** @returns Bluebird<string> */
function waitOneSecond() {
// return a promise that resolves after 1 second
// @ts-ignore TS2351 (new Cypress.Promise)
return new Cypress.Promise((resolve, reject) => {
setTimeout(() => {
// set waited to true
waited = true;
// resolve with 'foo' string
resolve('foo');
}, 1000);
});
}
cy.then(() =>
// return a promise to cy.then() that
// is awaited until it resolves
// @ts-ignore TS7006
waitOneSecond().then((str) => {
expect(str).to.eq('foo');
expect(waited).to.be.true;
})
);
});
});

View File

@@ -1,59 +0,0 @@
/// <reference types="Cypress" />
context('Viewport', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/viewport');
});
it('cy.viewport() - set the viewport size and dimension', () => {
// https://on.cypress.io/viewport
cy.get('#navbar').should('be.visible');
cy.viewport(320, 480);
// the navbar should have collapse since our screen is smaller
cy.get('#navbar').should('not.be.visible');
cy.get('.navbar-toggle').should('be.visible').click();
cy.get('.nav').find('a').should('be.visible');
// lets see what our app looks like on a super large screen
cy.viewport(2999, 2999);
// cy.viewport() accepts a set of preset sizes
// to easily set the screen to a device's width and height
// We added a cy.wait() between each viewport change so you can see
// the change otherwise it is a little too fast to see :)
cy.viewport('macbook-15');
cy.wait(200);
cy.viewport('macbook-13');
cy.wait(200);
cy.viewport('macbook-11');
cy.wait(200);
cy.viewport('ipad-2');
cy.wait(200);
cy.viewport('ipad-mini');
cy.wait(200);
cy.viewport('iphone-6+');
cy.wait(200);
cy.viewport('iphone-6');
cy.wait(200);
cy.viewport('iphone-5');
cy.wait(200);
cy.viewport('iphone-4');
cy.wait(200);
cy.viewport('iphone-3');
cy.wait(200);
// cy.viewport() accepts an orientation for all presets
// the default orientation is 'portrait'
cy.viewport('ipad-2', 'portrait');
cy.wait(200);
cy.viewport('iphone-4', 'landscape');
cy.wait(200);
// The viewport will be reset back to the default dimensions
// in between tests (the default can be set in cypress.json)
});
});

View File

@@ -1,33 +0,0 @@
/// <reference types="Cypress" />
context('Waiting', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/waiting');
});
// BE CAREFUL of adding unnecessary wait times.
// https://on.cypress.io/best-practices#Unnecessary-Waiting
// https://on.cypress.io/wait
it('cy.wait() - wait for a specific amount of time', () => {
cy.get('.wait-input1').type('Wait 1000ms after typing');
cy.wait(1000);
cy.get('.wait-input2').type('Wait 1000ms after typing');
cy.wait(1000);
cy.get('.wait-input3').type('Wait 1000ms after typing');
cy.wait(1000);
});
it('cy.wait() - wait for a specific route', () => {
cy.server();
// Listen to GET to comments/1
cy.route('GET', 'comments/*').as('getComment');
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.network-btn').click();
// wait for GET comments/1
cy.wait('@getComment').its('status').should('eq', 200);
});
});

View File

@@ -1,22 +0,0 @@
/// <reference types="Cypress" />
context('Window', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/window');
});
it('cy.window() - get the global window object', () => {
// https://on.cypress.io/window
cy.window().should('have.property', 'top');
});
it('cy.document() - get the document object', () => {
// https://on.cypress.io/document
cy.document().should('have.property', 'charset').and('eq', 'UTF-8');
});
it('cy.title() - get the title', () => {
// https://on.cypress.io/title
cy.title().should('include', 'Kitchen Sink');
});
});

View File

@@ -1,5 +0,0 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@@ -18,7 +18,7 @@ export const mermaidUrl = (graphStr, options, api) => {
return url;
};
export const imgSnapshotTest = (graphStr, _options, api) => {
export const imgSnapshotTest = (graphStr, _options, api = false, validation) => {
cy.log(_options);
const options = Object.assign(_options);
if (!options.fontFamily) {
@@ -42,16 +42,32 @@ export const imgSnapshotTest = (graphStr, _options, api) => {
if (!options.fontSize) {
options.fontSize = '16px';
}
cy.log(options);
const useAppli = Cypress.env('useAppli');
const branch = Cypress.env('codeBranch');
cy.log('Hello ' + useAppli ? 'Appli' : 'image-snapshot');
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
if (useAppli) {
cy.eyesOpen({
appName: 'Mermaid-' + branch,
testName: name,
batchName: branch,
});
}
const url = mermaidUrl(graphStr, options, api);
cy.visit(url);
if (validation) cy.get('svg').should(validation);
cy.get('svg');
// cy.percySnapshot();
// Default name to test title
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
cy.matchImageSnapshot(name);
if (useAppli) {
cy.eyesCheckWindow('Click!');
cy.eyesClose();
} else {
cy.matchImageSnapshot(name);
}
};
export const renderGraph = (graphStr, options, api) => {

View File

@@ -1,105 +0,0 @@
import { imgSnapshotTest } from '../../helpers/util.js';
describe('Git Graph diagram', () => {
it('1: should render a simple gitgraph with commit on main branch', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
commit id: "3"
`,
{}
);
});
it('2: should render a simple gitgraph with commit on main branch with Id', () => {
imgSnapshotTest(
`gitGraph
commit id: "One"
commit id: "Two"
commit id: "Three"
`,
{}
);
});
it('3: should render a simple gitgraph with different commitTypes on main branch ', () => {
imgSnapshotTest(
`gitGraph
commit id: "Normal Commit"
commit id: "Reverse Commit" type: REVERSE
commit id: "Hightlight Commit" type: HIGHLIGHT
`,
{}
);
});
it('4: should render a simple gitgraph with tags commitTypes on main branch ', () => {
imgSnapshotTest(
`gitGraph
commit id: "Normal Commit with tag" tag: "v1.0.0"
commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1"
commit id: "Hightlight Commit" type: HIGHLIGHT tag: "8.8.4"
`,
{}
);
});
it('5: should render a simple gitgraph with two branches', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
branch develop
checkout develop
commit id: "3"
commit id: "4"
checkout main
commit id: "5"
commit id: "6"
`,
{}
);
});
it('6: should render a simple gitgraph with two branches and merge commit', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
branch develop
checkout develop
commit id: "3"
commit id: "4"
checkout main
merge develop
commit id: "5"
commit id: "6"
`,
{}
);
});
it('7: should render a simple gitgraph with three branches and merge commit', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
branch nice_feature
checkout nice_feature
commit id: "3"
checkout main
commit id: "4"
checkout nice_feature
branch very_nice_feature
checkout very_nice_feature
commit id: "5"
checkout main
commit id: "6"
checkout nice_feature
commit id: "7"
checkout main
merge nice_feature
checkout very_nice_feature
commit id: "8"
checkout main
commit id: "9"
`,
{}
);
});
});

View File

@@ -1,49 +0,0 @@
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js';
describe('Requirement diagram', () => {
it('sample', () => {
imgSnapshotTest(
`
requirementDiagram
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
functionalRequirement test_req2 {
id: 1.1
text: the second test text.
risk: low
verifymethod: inspection
}
performanceRequirement test_req3 {
id: 1.2
text: the third test text.
risk: medium
verifymethod: demonstration
}
element test_entity {
type: simulation
}
element test_entity2 {
type: word doc
docRef: reqs/test_entity
}
test_entity - satisfies -> test_req2
test_req - traces -> test_req2
test_req - contains -> test_req3
test_req <- copies - test_entity2
`,
{}
);
cy.get('svg');
});
});

View File

@@ -78,7 +78,7 @@
a_a --> c --> d_d --> c_c
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
class a_a apa;
click a_a "http://www.aftonbladet.se" "apa"
click a_a "https://www.aftonbladet.se" "apa"
</div>

View File

@@ -22,16 +22,16 @@
<body>
<h1>info below</h1>
<div class="flex">
<div class="mermaid2" style="width: 50%; height: 20%;">
<div class="mermaid" style="width: 50%; height: 20%;">
flowchart BT
subgraph two
b1
end
subgraph three
c1-->c2
end
c1 --apa apa apa--> b1
two --> c2
subgraph S1
sub1 -->sub2
end
subgraph S2
sub4
end
S1 --> S2
sub1 --> sub4
</div>
<div class="mermaid2" style="width: 50%; height: 200px;">
sequenceDiagram
@@ -163,7 +163,7 @@ _one --> b
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { curve: 'cardinal', htmlLabels: true },
flowchart: { curve: 'cardinal', htmlLabels: false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated

View File

@@ -9,7 +9,7 @@
<style>
body {
/* background: rgb(221, 208, 208); */
background:#111;
/* background:#111; */
/* background:#333; */
font-family: 'Arial';
}
@@ -26,24 +26,33 @@
</head>
<body>
<h1>info below</h1>
<div class="mermaid2" style="width: 100%; height: 20%;">
%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%%
<div class="mermaid" style="width: 100%; height: 20%;">
%%{init: { "logLevel": "debug", "theme": "default" , "gitGraph" : {"showBranches":"false"},"themeVariables": {
"gitBranchLabel0": "#ff0000",
"gitBranchLabel1": "#00ff00",
"gitBranchLabel2": "#0000ff",
"git0": "#550055"
} } }%%
gitGraph
commit "Ashish"
branch newbranch
checkout newbranch
commit id:"1111"
commit tag:"test"
accTitle: "Git Graph"
accDescr {
Git Graph description.
Multiline description
}
commit
branch develop
commit tag:"v1.0.0"
commit
checkout main
commit type: HIGHLIGHT
commit
merge newbranch
merge develop
commit
branch b2
branch featureA
commit
</div>
<div class="mermaid" style="width: 100%; height: 20%;">
<div class="mermaid2" style="width: 100%; height: 20%;">
gitGraph
commit type:HIGHLIGHT
branch hotfix
@@ -101,18 +110,19 @@
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'dark',
// themeVariables: {
// primaryColor: '#9400D3',
// darkMode: true,
// background: '#222',
// // textColor: 'white',
// // primaryTextColor: '#f4f4f4',
//theme: 'dark',
themeVariables: {
commitLabelColor: '#9400D3',
commitLabelBackground: '#FFFFFF',
// darkMode: true,
// background: '#222',
// // textColor: 'white',
// // primaryTextColor: '#f4f4f4',
// // // nodeBkg: '#ff0000',
// // // mainBkg: '#0000ff',
// // // tertiaryColor: '#ffffcc',
// },
// // // nodeBkg: '#ff0000',
// // // mainBkg: '#0000ff',
// // // tertiaryColor: '#ffffcc',
},
// theme: 'forest',
// theme: 'neutral',
// theme: 'dark',

View File

@@ -9,7 +9,7 @@
<style>
body {
/* background: rgb(221, 208, 208); */
background:#111;
/* background:#111; */
/* background:#333; */
font-family: 'Arial';
}
@@ -43,6 +43,7 @@
</div>
<div class="mermaid" style="width: 100%; height: 20%;">
%%{init: { "gitGraph": { "showBranches": true, "mainBranchName": "APA" }}}%%
gitGraph
commit
branch hotfix
@@ -54,14 +55,14 @@
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout APA
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
checkout APA
merge hotfix
checkout featureB
commit
@@ -79,10 +80,10 @@
branch release
checkout release
commit
checkout main
checkout APA
commit
checkout release
merge main
merge APA
checkout develop
merge release
@@ -101,7 +102,7 @@
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'dark',
theme: 'default',
themeVariables: {
// primaryColor: '#9400D3',
// darkMode: false,
@@ -119,6 +120,7 @@
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 1,
flowchart: { curve: 'linear', htmlLabels: true },
// gitGraph: { showCommitLabel: false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated

View File

@@ -26,71 +26,82 @@
</style>
</head>
<body>
<div class="mermaid2" style="width: 50%;">
pie title Pets adopted by volunteers
"Dogs" : 386
"Cats" : 85
"Rats" : 15
</div>
<div class="mermaid2" style="width: 100%;">
gantt
title Adding GANTT diagram functionality to mermaid
excludes :excludes the named dates/days from being included in a charted task..
section Screening
Lexplore :active, des1, 2023-01-06,2023-01-08
H4 :active, des2, 2024-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
</div>
<div class="mermaid2" style="width: 50%;">
journey
title Adding journey diagram functionality to mermaid
accTitle: Adding acc journey diagram functionality to mermaid
accDescr {
My multi-line description
of the diagram
}
section Order from website
</div>
<div class="mermaid2" style="width: 50%;">
pie
accTitle: My Pie Chart Accessibility Title
accDescr: My Pie Chart Accessibility Description
title Key elements in Product X
"Calcium" : 42.96
"Potassium" : 50.05
"Magnesium" : 10.01
"Iron" : 5
</div>
<div class="mermaid2" style="width: 50%;">
gitGraph
accTitle: My Gitgraph Accessibility Title
accDescr: My Gitgraph Accessibility Description
commit
commit
branch develop
checkout develop
commit
commit
checkout main
merge develop
commit
commit
</div>
<div class="mermaid2" style="width: 50%;">
sequenceDiagram
title: My Sequence Diagram Title
accTitle: My Acc Sequence Diagram
accDescr: My Sequence Diagram Description
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
</div>
<div class="mermaid2" style="width: 50%;">
graph TD
A -->|000| B
B -->|111| C
linkStyle 1 stroke:#ff3,stroke-width:4px,color:red;
</div>
<div class="mermaid2" style="width: 100%;">
info
</div>
<div class="mermaid2" style="width: 100%;">
gitGraph:
options
{
"nodeSpacing": 150,
"nodeRadius": 10
}
end
commit
branch newbranch
checkout newbranch
commit
commit
checkout master
commit
commit
merge newbranch
</div>
<div class="mermaid" style="width: 50%;">
sequenceDiagram
title: with colon:
participant a as Alice
participant j as John
note right of a: Hello world!
properties a: {"class": "internal-service-actor", "type": "@clock"}
properties j: {"class": "external-service-actor", "type": "@computer"}
links a: {"Repo": "https://www.contoso.com/repo", "Swagger": "https://www.contoso.com/swagger"}
links j: {"Repo": "https://www.contoso.com/repo"}
links a: {"Dashboard": "https://www.contoso.com/dashboard", "On-Call": "https://www.contoso.com/oncall"}
link a: Contacts @ https://contacts.contoso.com/?contact=alice@contoso.com
a->>j: Hello John, how are you?
j-->>a: Great! </div>
<div class="mermaid2" style="width: 100%;">
journey
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
journey
accTitle: My User Journey Diagram
accDescr: My User Journey Diagram Description
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
</div>
<div class="mermaid2" style="width: 100%;">
requirementDiagram
accTitle: My req Diagram
accDescr: My req Diagram Description
requirement test_req {
id: 1
@@ -128,71 +139,38 @@ requirementDiagram
test_req - contains -> test_req3
test_req <- copies - test_entity2
</div>
<div class="mermaid2" style="width: 100%;">
erDiagram
CUSTOMER }|..|{ DELIVERY-ADDRESS : has
CUSTOMER ||--o{ ORDER : places
CUSTOMER ||--o{ INVOICE : "liable for"
DELIVERY-ADDRESS ||--o{ ORDER : receives
INVOICE ||--|{ ORDER : covers
ORDER ||--|{ ORDER-ITEM : includes
PRODUCT-CATEGORY ||--|{ PRODUCT : contains
PRODUCT ||--o{ ORDER-ITEM : "ordered in"
<div class="mermaid" style="width: 100%;">
stateDiagram
state Active {
Idle
}
Inactive --> Idle: ACT
Active --> Active: LOG
</div>
<div class="mermaid2" style="width: 100%;">
graph TB
accTitle: My flowchart
accDescr: My flowchart Description
subgraph One
a1-->a2-->a3
end
</div>
<div class="mermaid" style="width: 50%;">
flowchart LR
Function-->URL-->A-->B-->C
click Function clickByFlow "Add a div"
click URL "https://mermaid-js.github.io/mermaid/#/" "Visit <strong>mermaid docs</strong>" _blank
</div>
<div class="mermaid2" style="width: 100%;">
gantt
dateFormat YYYY-MM-DD
axisFormat %d/%m
title Adding GANTT diagram to mermaid
excludes weekdays 2014-01-10
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h
section Clickable
Visit mermaidjs :active, cl1, 2014-01-07,2014-01-10
Calling a Callback (look at the console log) :cl2, after cl1, 3d
Calling a Callback with args :cl3, after cl1, 3d
click cl1 href "https://mermaid-js.github.io/mermaid/#/"
click cl2 call clickByGantt()
click cl3 call clickByGantt("test1", test2, test3)
section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page : 20h
Add another diagram to demo page : 48h
sequenceDiagram
A ->> B: 1
rect rgb(204, 0, 102)
break yes
rect rgb(0, 204, 204)
C ->> C: 0
end
end
end
B ->> A: Return
</div>
<div class="mermaid2" style="width: 100%;">
classDiagram
accTitle: My class diagram
accDescr: My class diagram Description
Class01 <|-- AveryLongClass : Cool
Class09 --> C2 : Where am i?
Class09 --* C3
@@ -209,6 +187,8 @@ class Class10 {
</div>
<div class="mermaid2" style="width: 100%;">
stateDiagram
accTitle: Apa
accDescr: One that can climb better then any man
[*] --> S1
state "Some long name" as S1
</div>
@@ -250,26 +230,27 @@ class Class10 {
nodeSpacing: 10,
curve: 'cardinal',
htmlLabels: true,
defaultRenderer: 'dagre-d3',
useMaxWidth: false,
// defaultRenderer: 'dagre-d3',
},
class: {
defaultRenderer: 'dagre-d3',
// defaultRenderer: 'dagre-d3',
htmlLabels: true,
},
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: {
actorFontFamily: 'courier',
actorMargin: 50,
showSequenceNumbers: false,
// forceMenus: true,
},
// sequenceDiagram: { actorMargin: 300, forceMenus: false }, // deprecated
// sequence: {
// actorFontFamily: 'courier',
// actorMargin: 50,
// showSequenceNumbers: false,
// // hideUnusedParticipants: true,
// // forceMenus: true,
// },
// // sequenceDiagram: { actorMargin: 300, forceMenus: false }, // deprecated
// fontFamily: '"times", sans-serif',
// fontFamily: 'courier',
state: {
nodeSpacing: 50,
rankSpacing: 50,
defaultRenderer: 'dagre-d3',
},
logLevel: 0,
fontSize: 18,

View File

@@ -11,52 +11,207 @@
body {
/* background: rgb(221, 208, 208); */
/* background:#333; */
font-family: 'Arial';
font-family: 'Courier New', Courier, monospace;
/* font-size: 18px !important; */
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.mermaid svg {
.mermaid {
border: 1px solid red;
font-family: 'Courier New', Courier, monospace;
/* font-size: 18px !important; */
}
</style>
</head>
<body>
<div>info below</div>
<div class="flex">
<div class="">
<div class="mermaid2" style="width: 100%; height: 400px;">
%%{init: { "logLevel": 1, "er": {"fontSize":18 }} }%%
erDiagram
CUSTOMER }|..|{ DELIVERY-ADDRESS : has
CUSTOMER ||--o{ ORDER : places
CUSTOMER ||--o{ INVOICE : "liable for"
DELIVERY-ADDRESS ||--o{ ORDER : receives
INVOICE ||--|{ ORDER : covers
ORDER ||--|{ ORDER-ITEM : includes
PRODUCT-CATEGORY ||--|{ PRODUCT : contains
PRODUCT ||--o{ ORDER-ITEM : "ordered in"
flowchart TB;subgraph "number as labels";1;end;
</div>
<div class="mermaid2" style="width: 50%; height: 400px;">
<div class="mermaid2" style="width: 100%; height: 400px;">
flowchart TB;a[APA];
</div>
<div class="mermaid2" style="margin-left:100px;">
graph TD
work --> sleep
sleep --> work
eat --> sleep
work --> eat
</div>
<div class="mermaid2" style="margin-left:100px;">
flowchart TD
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
subgraph T ["Test"]
A
B
C
end
work --> sleep
sleep --> work
eat --> sleep
work --> eat
</div>
<div class="mermaid2" style="">
graph TB
A
B
subgraph foo[Foo SubGraph]
C
D
end
subgraph bar[Bar SubGraph]
E
F
end
G
classDef Test fill:#F84E68,stroke:#333,color:white;
class A,T Test
classDef TestSub fill:green;
class T TestSub
linkStyle 0,1 color:orange, stroke: orange;
A-->B
B-->C
C-->D
B-->D
D-->E
E-->A
E-->F
F-->D
F-->G
B-->G
G-->D
style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred
style bar fill:#999,stroke-width:2px,stroke:#0F0,color:blue
</div>
<div class="mermaid2" style="">
graph TB
%%{init: { "logLevel": 1, "flowchart": {"htmlLabels":true }} }%%
A
B
subgraph foo[Foo SubGraph]
C
D
end
subgraph bar[Bar SubGraph]
E
F
end
G
A-->B
B-->C
C-->D
B-->D
D-->E
E-->A
E-->F
F-->D
F-->G
B-->G
G-->D
style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred
style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue
</div>
<div class="mermaid2" style="">
graph TD
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
</div>
<div class="mermaid2" style="">
graph TD
%%{init: { "logLevel": 1, "flowchart": {"htmlLabels":true }} }%%
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
</div>
<div class="mermaid2" style="">
flowchart TD
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
</div>
<div class="mermaid2" style="">
flowchart TD
%%{init: { "logLevel": 1, "flowchart": {"htmlLabels":true }} }%%
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
</div>
<div class="mermaid2" style="">
flowchart LR
a["<strong>Haiya</strong>"]---->b
</div>
<div class="mermaid" style="width: 100%; height: 20%;">
flowchart TB
<div class="mermaid" style="">
flowchart LR
%%{init: { "logLevel": 1, "flowchart": {"htmlLabels":true }} }%%
a["<strong>Haiya</strong>"]---->b
</div>
<div class="mermaid2" style="">
flowchart TD
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
</div>
<div class="mermaid2" style="">
flowchart TD
%%{init: { "logLevel": 1, "flowchart": {"htmlLabels":true }} }%%
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
</div>
<div class="mermaid2" style="">
%%{init: { "logLevel": 1, "flowchart": {"htmlLabels":true }} }%%
classDiagram-v2
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class12 <|.. Class08
Class11 ..>Class12
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
</div>
<div class="mermaid2" style="">
classDiagram-v2
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class12 <|.. Class08
Class11 ..>Class12
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
</div>
<div class="mermaid" style="">
flowchart BT
subgraph S1
sub1 -->sub2
end
@@ -66,141 +221,25 @@ flowchart TB
S1 --> S2
sub1 --> sub4
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
flowchart TB
c1-->a2
subgraph one
a1-->a2
end
subgraph two
b1-->b2
end
subgraph three
c1-->c2
end
one --> two
three --> two
two --> c2
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
stateDiagram-v2
state S1 {
sub1 -->sub2
}
state S2 {
sub4
}
S1 --> S2
sub1 --> sub4
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
requirementDiagram
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
functionalRequirement test_req2 {
id: 1.1
text: the second test text.
risk: low
verifymethod: inspection
}
performanceRequirement test_req3 {
id: 1.2
text: the third test text.
risk: medium
verifymethod: demonstration
}
element test_entity {
type: simulation
}
element test_entity2 {
type: word doc
docRef: reqs/test_entity
}
test_entity - satisfies -> test_req2
test_req - traces -> test_req2
test_req - contains -> test_req3
test_req <- copies - test_entity2
</div>
<div class="mermaid2" style="width: 50%; height: 20%;">
flowchart LR
classDef dark fill:#000,stroke:#000,stroke-width:4px,color:#fff
Lorem --> Ipsum --> Dolor
class Lorem,Dolor dark
</div>
<div class="mermaid2" style="width: 50%; height: 20%;">
%%{init: {'theme': 'base' }}%%
%%{init2: { 'logLevel': 0, 'theme': 'forest'} }%%
flowchart TD
L1 --- L2
L2 --- C
M1 ---> C
R1 .-> R2
R2 <.-> C
C -->|Label 1| E1
C <-- Label 2 ---> E2
C ----> E3
C <-...-> E4
C ======> E5
</div>
<div class="mermaid2" style="width: 50%; height: 21%;">
flowchart LR
A[red text] -->|default style| B(blue text)
C([red text]) -->|default style| D[[blue text]]
E[(red text)] -->|default style| F((blue text))
G>red text] -->|default style| H{blue text}
I{{red text}} -->|default style| J[/blue text/]
K[
ed text] -->|default style| L[/blue text]
M[
ed text/] -->|default style| N[blue text]
linkStyle default color:Sienna;
style A stroke:#ff0000,fill:#ffcccc,color:#ff0000
style B stroke:#0000ff,fill:#ccccff,color:#0000ff
style C stroke:#ff0000,fill:#ffcccc,color:#ff0000
style D stroke:#0000ff,fill:#ccccff,color:#0000ff
style E stroke:#ff0000,fill:#ffcccc,color:#ff0000
style F stroke:#0000ff,fill:#ccccff,color:#0000ff
style G stroke:#ff0000,fill:#ffcccc,color:#ff0000
style H stroke:#0000ff,fill:#ccccff,color:#0000ff
style I stroke:#ff0000,fill:#ffcccc,color:#ff0000
style J stroke:#0000ff,fill:#ccccff,color:#0000ff
style K stroke:#ff0000,fill:#ffcccc,color:#ff0000
style L stroke:#0000ff,fill:#ccccff,color:#0000ff
style M stroke:#ff0000,fill:#ffcccc,color:#ff0000
style N stroke:#0000ff,fill:#ccccff,color:#0000ff
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'neutral',
arrowMarkerAbsolute: true,
// theme: 'neutral',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { nodeSpacing: 10, curve: 'cardinal', htmlLabels: true },
htmlLabels: true,
flowchart: { curve: 'cardinal', htmlLabels: false },
// htmlLabels: true,
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorFontFamily: 'courier', actorMargin: 50, showSequenceNumbers: false },
// sequence: { actorFontFamily: 'courier', actorMargin: 50, showSequenceNumbers: false },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"times", sans-serif',
// fontFamily: 'courier',
fontSize: 18,
curve: 'cardinal',
fontFamily: 'courier',
// fontSize: 18,
// curve: 'cardinal',
securityLevel: 'loose',
// themeVariables: {relationLabelColor: 'red'}
});

105
cypress/platform/xss20.html Normal file
View File

@@ -0,0 +1,105 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<style>
body {
/* background: rgb(221, 208, 208); */
/* background:#333; */
font-family: 'Arial';
/* font-size: 18px !important; */
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.mermaid svg {
/* font-size: 18px !important; */
}
.malware {
position: fixed;
bottom:0;
left:0;
right:0;
height: 150px;
background: red;
color: black;
display: flex;
display: flex;
justify-content: center;
align-items: center;
font-family: monospace;
font-size: 72px;
}
</style>
</head>
<body>
<div>Security check</div>
<div class="flex">
<div id="diagram" class="mermaid"></div>
<div id="res" class=""></div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'forest',
arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 5,
state: {
defaultRenderer: 'dagre-d3',
},
flowchart: {
// defaultRenderer: 'dagre-wrapper',
nodeSpacing: 10,
curve: 'cardinal',
htmlLabels: true,
},
htmlLabels: true,
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorFontFamily: 'courier', actorMargin: 50, showSequenceNumbers: false },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"times", sans-serif',
// fontFamily: 'courier',
fontSize: 18,
curve: 'basis',
// securityLevel: 'loose',
startOnLoad: false,
secure: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize'],
// themeVariables: {relationLabelColor: 'red'}
});
function callback() {
alert('It worked');
}
function xssAttack() {
const div = document.createElement('div');
div.id = 'the-malware';
div.className = 'malware';
div.innerHTML = 'XSS Succeeded';
document.getElementsByTagName('body')[0].appendChild(div);
throw new Error('XSS Succeded');
}
// var diagram = ` graph TD
// A --> B["&lt;a href='javasc`;
// diagram += `ript#colon;xssAttack()'&gt;AAA&lt;/a&gt;"]`;
var diagram = ` graph TD
A --> B["<a href='javasc`;
diagram += `ript#colon;xssAttack()'>AAA</a>"]`;
// diagram += '//via.placeholder.com/64\' width=64 />"]';
// document.querySelector('#diagram').innerHTML = diagram;
mermaid.render('diagram', diagram, (res) => {
// console.log(res);
document.querySelector('#res').innerHTML = res;
});
</script>
</body>
</html>

105
cypress/platform/xss21.html Normal file
View File

@@ -0,0 +1,105 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<style>
body {
/* background: rgb(221, 208, 208); */
/* background:#333; */
font-family: 'Arial';
/* font-size: 18px !important; */
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.mermaid svg {
/* font-size: 18px !important; */
}
.malware {
position: fixed;
bottom:0;
left:0;
right:0;
height: 150px;
background: red;
color: black;
display: flex;
display: flex;
justify-content: center;
align-items: center;
font-family: monospace;
font-size: 72px;
}
</style>
</head>
<body>
<div>Security check</div>
<div class="flex">
<div id="diagram" class="mermaid"></div>
<div id="res" class=""></div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'forest',
arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
state: {
defaultRenderer: 'dagre-d3',
},
flowchart: {
// defaultRenderer: 'dagre-wrapper',
nodeSpacing: 10,
curve: 'cardinal',
htmlLabels: true,
},
htmlLabels: true,
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorFontFamily: 'courier', actorMargin: 50, showSequenceNumbers: false },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"times", sans-serif',
// fontFamily: 'courier',
fontSize: 18,
curve: 'basis',
// securityLevel: 'loose',
startOnLoad: false,
secure: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize'],
// themeVariables: {relationLabelColor: 'red'}
});
function callback() {
alert('It worked');
}
function xssAttack() {
const div = document.createElement('div');
div.id = 'the-malware';
div.className = 'malware';
div.innerHTML = 'XSS Succeeded';
document.getElementsByTagName('body')[0].appendChild(div);
throw new Error('XSS Succeded');
}
// var diagram = ` graph TD
// A --> B["&lt;a href='javasc`;
// diagram += `ript#colon;xssAttack()'&gt;AAA&lt;/a&gt;"]`;
var diagram = ` graph TD
A --> B["<a href='javasc`;
diagram += `ript#9;t#colon;xssAttack()'>AAA</a>"]`;
// diagram += '//via.placeholder.com/64\' width=64 />"]';
// document.querySelector('#diagram').innerHTML = diagram;
mermaid.render('diagram', diagram, (res) => {
console.log(res);
document.querySelector('#res').innerHTML = res;
});
</script>
</body>
</html>

View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<div class="mermaid">
graph TD
A --&gt; B["&lt;a href='javascript#9;t#colon;alert(document.location)'&gt;AAA&lt;/a&gt;"]
</div>
<script src="./mermaid.js"></script>
<script>mermaid.initialize({ startOnLoad: true });
</script>
</body>
</html>

View File

@@ -1,23 +0,0 @@
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
// module.exports = (on, config) => {
// // `on` is used to hook into various events Cypress emits
// // `config` is the resolved Cypress config
// }
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
module.exports = (on, config) => {
addMatchImageSnapshotPlugin(on, config);
};

1
cypress/support/eyes-index.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
import "@applitools/eyes-cypress"

View File

@@ -13,9 +13,12 @@
// https://on.cypress.io/configuration
// ***********************************************************
import '@applitools/eyes-cypress/commands';
// Import commands.js using ES2015 syntax:
import './commands';
// import '@percy/cypress';
import '@applitools/eyes-cypress/commands';
// Alternatively you can use CommonJS syntax:
// require('./commands')

62
demos/classchart.html Normal file
View File

@@ -0,0 +1,62 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<style>
div.mermaid {
/* font-family: 'trebuchet ms', verdana, arial; */
font-family: 'Courier New', Courier, monospace !important;
}
</style>
</head>
<body>
<div class="mermaid">
classDiagram
title Animal Diagram
accDescription The animal class diagram
Animal <|-- Duck
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
theme: 'forest',
// themeCSS: '.node rect { fill: red; }',
logLevel: 3,
securityLevel: 'loose',
flowchart: { curve: 'basis' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
// sequenceDiagram: { actorMargin: 300 } // deprecated
});
</script>
</body>
</html>

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<title>Mermaid Quick Flowchart Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<style>
div.mermaid {
@@ -220,6 +220,8 @@
<h3>graph</h3>
<div class="mermaid">
graph TD
title What to buy
accDescription Options of what to buy with Christmas money
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me thinksssssx<br/>sssssssssssssssssssuuu<br />tttsssssssssssssssssssssss}
C -->|One| D[Laptop]
@@ -230,8 +232,8 @@
<h3>flowchart</h3>
<div class="mermaid">
flowchart TD
title Christmas
accDescription Get money
title What to buy
accDescription Options of what to buy with Christmas money
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me thinksssssx<br/>sssssssssssssssssssuuu<br />tttsssssssssssssssssssssss}
C -->|One| D[Laptop]

43
demos/gantt.html Normal file
View File

@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<style>
div.mermaid {
font-family: 'Courier New', Courier, monospace !important;
}
</style>
</head>
<body>
<!-- accDescription Tasks for Q4 -->
<div class="mermaid">
gantt
title A Gantt Diagram
accDescription Remaining Q4 Tasks
dateFormat YYYY-MM-DD
section Section
A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d
section Another
Task in sec :2014-01-12 , 12d
another task : 24d
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
logLevel: 3,
securityLevel: 'loose',
gantt: { axisFormat: '%m/%d/%Y' },
});
</script>
</body>
</html>

View File

@@ -20,6 +20,165 @@
</div>
<hr />
<div class="mermaid">
C4Context
title System Context diagram for Internet Banking System
Enterprise_Boundary(b0, "BankBoundary0") {
Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.")
Person(customerB, "Banking Customer B")
Person_Ext(customerC, "Banking Customer C", "desc")
Person(customerD, "Banking Customer D", "A customer of the bank, <br/> with personal bank accounts.")
System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.")
Enterprise_Boundary(b1, "BankBoundary") {
SystemDb_Ext(SystemE, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
System_Boundary(b2, "BankBoundary2") {
System(SystemA, "Banking System A")
System(SystemB, "Banking System B", "A system of the bank, with personal bank accounts. next line.")
}
System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.")
SystemDb(SystemD, "Banking System D Database", "A system of the bank, with personal bank accounts.")
Boundary(b3, "BankBoundary3", "boundary") {
SystemQueue(SystemF, "Banking System F Queue", "A system of the bank.")
SystemQueue_Ext(SystemG, "Banking System G Queue", "A system of the bank, with personal bank accounts.")
}
}
}
BiRel(customerA, SystemAA, "Uses")
BiRel(SystemAA, SystemE, "Uses")
Rel(SystemAA, SystemC, "Sends e-mails", "SMTP")
Rel(SystemC, customerA, "Sends e-mails to")
</div>
<div class="mermaid">
C4Container
title Container diagram for Internet Banking System
System_Ext(email_system, "E-Mail System", "The internal Microsoft Exchange system")
Person(customer, Customer, "A customer of the bank, with personal bank accounts")
Container_Boundary(c1, "Internet Banking") {
Container(spa, "Single-Page App", "JavaScript, Angular", "Provides all the Internet banking functionality to cutomers via their web browser")
Container_Ext(mobile_app, "Mobile App", "C#, Xamarin", "Provides a limited subset of the Internet banking functionality to customers via their mobile device")
Container(web_app, "Web Application", "Java, Spring MVC", "Delivers the static content and the Internet banking SPA")
ContainerDb(database, "Database", "SQL Database", "Stores user registration information, hashed auth credentials, access logs, etc.")
ContainerDb_Ext(backend_api, "API Application", "Java, Docker Container", "Provides Internet banking functionality via API")
}
System_Ext(banking_system, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
Rel(customer, web_app, "Uses", "HTTPS")
Rel(customer, spa, "Uses", "HTTPS")
Rel(customer, mobile_app, "Uses")
Rel(web_app, spa, "Delivers")
Rel(spa, backend_api, "Uses", "async, JSON/HTTPS")
Rel(mobile_app, backend_api, "Uses", "async, JSON/HTTPS")
Rel_Back(database, backend_api, "Reads from and writes to", "sync, JDBC")
Rel(email_system, customer, "Sends e-mails to")
Rel(backend_api, email_system, "Sends e-mails using", "sync, SMTP")
Rel(backend_api, banking_system, "Uses", "sync/async, XML/HTTPS")
</div>
<div class="mermaid">
C4Component
title Component diagram for Internet Banking System - API Application
Container(spa, "Single Page Application", "javascript and angular", "Provides all the internet banking functionality to customers via their web browser.")
Container(ma, "Mobile App", "Xamarin", "Provides a limited subset ot the internet banking functionality to customers via their mobile mobile device.")
ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
System_Ext(mbs, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
Container_Boundary(api, "API Application") {
Component(sign, "Sign In Controller", "MVC Rest Controlle", "Allows users to sign in to the internet banking system")
Component(accounts, "Accounts Summary Controller", "MVC Rest Controller", "Provides customers with a summary of their bank accounts")
Component(security, "Security Component", "Spring Bean", "Provides functionality related to singing in, changing passwords, etc.")
Component(mbsfacade, "Mainframe Banking System Facade", "Spring Bean", "A facade onto the mainframe banking system.")
Rel(sign, security, "Uses")
Rel(accounts, mbsfacade, "Uses")
Rel(security, db, "Read & write to", "JDBC")
Rel(mbsfacade, mbs, "Uses", "XML/HTTPS")
}
Rel_Back(spa, sign, "Uses", "JSON/HTTPS")
Rel(spa, accounts, "Uses", "JSON/HTTPS")
Rel(ma, sign, "Uses", "JSON/HTTPS")
Rel(ma, accounts, "Uses", "JSON/HTTPS")
</div>
<div class="mermaid">
C4Dynamic
title Dynamic diagram for Internet Banking System - API Application
ContainerDb(c4, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
Container(c1, "Single-Page Application", "JavaScript and Angular", "Provides all of the Internet banking functionality to customers via their web browser.")
Container_Boundary(b, "API Application") {
Component(c3, "Security Component", "Spring Bean", "Provides functionality Related to signing in, changing passwords, etc.")
Component(c2, "Sign In Controller", "Spring MVC Rest Controller", "Allows users to sign in to the Internet Banking System.")
}
Rel(c1, c2, "Submits credentials to", "JSON/HTTPS")
Rel(c2, c3, "Calls isAuthenticated() on")
Rel(c3, c4, "select * from users where username = ?", "JDBC")
</div>
<div class="mermaid">
C4Deployment
title Deployment Diagram for Internet Banking System - Live
Deployment_Node(mob, "Customer's mobile device", "Apple IOS or Android"){
Container(mobile, "Mobile App", "Xamarin", "Provides a limited subset of the Internet Banking functionality to customers via their mobile device.")
}
Deployment_Node(comp, "Customer's computer", "Mircosoft Windows or Apple macOS"){
Deployment_Node(browser, "Web Browser", "Google Chrome, Mozilla Firefox,<br/> Apple Safari or Microsoft Edge"){
Container(spa, "Single Page Application", "JavaScript and Angular", "Provides all of the Internet Banking functionality to customers via their web browser.")
}
}
Deployment_Node(plc, "Big Bank plc", "Big Bank plc data center"){
Deployment_Node(dn, "bigbank-api*** x8", "Ubuntu 16.04 LTS"){
Deployment_Node(apache, "Apache Tomcat", "Apache Tomcat 8.x"){
Container(api, "API Application", "Java and Spring MVC", "Provides Internet Banking functionality via a JSON/HTTPS API.")
}
}
Deployment_Node(bb2, "bigbank-web*** x4", "Ubuntu 16.04 LTS"){
Deployment_Node(apache2, "Apache Tomcat", "Apache Tomcat 8.x"){
Container(web, "Web Application", "Java and Spring MVC", "Delivers the static content and the Internet Banking single page application.")
}
}
Deployment_Node(bigbankdb01, "bigbank-db01", "Ubuntu 16.04 LTS"){
Deployment_Node(oracle, "Oracle - Primary", "Oracle 12c"){
ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
}
}
Deployment_Node(bigbankdb02, "bigbank-db02", "Ubuntu 16.04 LTS") {
Deployment_Node(oracle2, "Oracle - Secondary", "Oracle 12c") {
ContainerDb(db2, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
}
}
}
Rel(mobile, api, "Makes API calls to", "json/HTTPS")
Rel(spa, api, "Makes API calls to", "json/HTTPS")
Rel_U(web, spa, "Delivers to the customer's web browser")
Rel(api, db, "Reads from and writes to", "JDBC")
Rel(api, db2, "Reads from and writes to", "JDBC")
Rel_R(db, db2, "Replicates data to")
</div>
<hr />
<div class="mermaid">
pie
title Key elements in Product X
@@ -385,8 +544,7 @@
A -->|Get money| B1[(Go shopping 1)]
A -->|Get money| B2[(Go shopping 2)]
A -->|Get money| B3[(Go shopping 3)]
C[(Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or
something to get around?)]
C[(Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?)]
B1 --> C
B2 --> C
B3 --> C
@@ -518,8 +676,10 @@
sequenceDiagram
autonumber
Alice->>John: Hello John,<br>how are you?
autonumber 50 10
Alice->>John: John,<br />can you hear me?
John-->>Alice: Hi Alice,<br />I can hear you!
autonumber off
John-->>Alice: I feel great!
</div>
@@ -601,10 +761,11 @@
gitGraph:
options
{
"nodeSpacing": 150,
"nodeRadius": 10
"nodeSpacing": 50,
"nodeRadius": 5
}
end
branch master
commit
branch newbranch
checkout newbranch
@@ -680,6 +841,7 @@
<div class="mermaid">
stateDiagram
accDescription This is a state diagram showing one state
State1
</div>
@@ -872,4 +1034,4 @@
</script>
</body>
</html>
</html>

45
demos/journey.html Normal file
View File

@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<style>
div.mermaid {
/* font-family: 'trebuchet ms', verdana, arial; */
font-family: 'Courier New', Courier, monospace !important;
}
</style>
</head>
<body>
<div class="mermaid">
journey
title My day
accDescription A user journey diagram of a typical day in my life
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 5: Me
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
theme: 'forest',
logLevel: 3,
securityLevel: 'loose',
flowchart: { curve: 'basis' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
});
</script>
</body>
</html>

106
demos/requirements.html Normal file
View File

@@ -0,0 +1,106 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<style>
div.mermaid {
/* font-family: 'trebuchet ms', verdana, arial; */
font-family: 'Courier New', Courier, monospace !important;
}
</style>
</head>
<body>
<div class="mermaid">
requirementDiagram
title This is a title
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
functionalRequirement test_req2 {
id: 1.1
text: the second test text.
risk: low
verifymethod: inspection
}
performanceRequirement test_req3 {
id: 1.2
text: the third test text.
risk: medium
verifymethod: demonstration
}
interfaceRequirement test_req4 {
id: 1.2.1
text: the fourth test text.
risk: medium
verifymethod: analysis
}
physicalRequirement test_req5 {
id: 1.2.2
text: the fifth test text.
risk: medium
verifymethod: analysis
}
designConstraint test_req6 {
id: 1.2.3
text: the sixth test text.
risk: medium
verifymethod: analysis
}
element test_entity {
type: simulation
}
element test_entity2 {
type: word doc
docRef: reqs/test_entity
}
element test_entity3 {
type: "test suite"
docRef: github.com/all_the_tests
}
test_entity - satisfies -> test_req2
test_req - traces -> test_req2
test_req - contains -> test_req3
test_req3 - contains -> test_req4
test_req4 - derives -> test_req5
test_req5 - refines -> test_req6
test_entity3 - verifies -> test_req5
test_req <- copies - test_entity2
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
theme: 'forest',
// themeCSS: '.node rect { fill: red; }',
logLevel: 3,
securityLevel: 'loose',
flowchart: { curve: 'basis' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
// sequenceDiagram: { actorMargin: 300 } // deprecated
});
</script>
</body>
</html>

View File

@@ -24,6 +24,7 @@
participant Alice
participant Bob
participant John as John<br />Second Line
autonumber 10 10
rect rgb(200, 220, 100)
rect rgb(200, 255, 200)
Alice ->> Bob: Hello Bob, how are you?
@@ -39,13 +40,17 @@
Bob-x John:wrap: John! Are you still debating about how you're doing? How long does it take??
Note over John: After a few more moments, John<br />finally snaps out of it.
end
autonumber off
alt either this
Alice->>John: Yes
Alice->>+John: Yes
John-->>-Alice: OK
else or this
autonumber
Alice->>John: No
else or this will happen
Alice->John: Maybe
end
autonumber 200
par this happens in parallel
Alice -->> Bob: Parallel message 1
and
@@ -69,4 +74,4 @@
</body>
</html>
</html>

50
demos/state.html Normal file
View File

@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Mermaid Quick Test Page</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
<style>
div.mermaid {
/* font-family: 'trebuchet ms', verdana, arial; */
font-family: 'Courier New', Courier, monospace !important;
}
</style>
</head>
<body>
<div class="mermaid">
stateDiagram
title This is a title
accDescription This is an accessible description
State1
</div>
<div class="mermaid">
stateDiagram-v2
title This is a title
accDescription This is an accessible description
State1
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
theme: 'forest',
// themeCSS: '.node rect { fill: red; }',
logLevel: 3,
securityLevel: 'loose',
flowchart: { curve: 'basis' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
// sequenceDiagram: { actorMargin: 300 } // deprecated
});
</script>
</body>
</html>

31406
dist/mermaid.core.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

129122
dist/mermaid.js vendored

File diff suppressed because one or more lines are too long

1
dist/mermaid.js.map vendored

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,7 @@
With version 8.6.0 comes the release of directives for mermaid, a new system for modifying configurations, with the aim of establishing centralized, sane defaults and simple implementation.
`directives` allow for a single-use overwriting of `config`, as it has been discussed in [Configurations](./Setup.md).
This allows site Diagram Authors to instantiate temporary modifications to `config` through the use of [Directives](), which are parsed before rendering diagram definitions. This allows the Diagram Authors to alter the appearance of the diagrams.
This allows site Diagram Authors to instantiate temporary modifications to `config` through the use of [Directives](), which are parsed before rendering diagram definitions. This allows the Diagram Authors to alter the appearance of the diagrams.
**A likely application for this is in the creation of diagrams/charts inside company/organizational webpages, that rely on mermaid for diagram and chart rendering.**
@@ -65,7 +65,7 @@ init would be an argument-directive: `%%{init: { **insert argument here**}}%%`
The json object that is passed as {**argument** } must be valid, quoted json or it will be ignored.
**for example**:
`%%{init: {"theme": default, "logLevel": 1 }}%%`
`%%{init: {"theme": "default", "logLevel": 1 }}%%`
Configurations that are passed through init cannot change the parameters in secure arrays of higher levels. In the event of a conflict, mermaid will give priority to secure arrays and parse the request, without changing the values of the parameters in conflict.
@@ -203,7 +203,7 @@ Ensures options parameter does not attempt to override siteConfig secure keys.
| Parameter | Description |Type | Required | Values|
| --- | --- | --- | --- | --- |
| conf| base set of values, which currentConfig coul be reset to.| Dictionary | Required | Any Values, with respect to the secure Array|
| conf| base set of values, which currentConfig could be reset to.| Dictionary | Required | Any Values, with respect to the secure Array|
```note
default: current siteConfig (optional, default `getSiteConfig()`)

View File

@@ -2,23 +2,23 @@
**Mermaid lets you create diagrams and visualizations using text and code.**
It is a Javascript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically.
It is a JavaScript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically.
>If you are familiar with Markdown you should have no problem learning [Mermaid's Syntax](./n00b-syntaxReference.md).
![banner](img/header.png)
<img src="img/header.png" alt="" />
<!-- **Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/README.md) -->
[![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
<!-- Mermaidn book banner -->
[![banner](img/book-banner-post-release.jpg)](https://mermaid-js.github.io/mermaid/landing/)
<!-- Mermaid book banner -->
[![Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!](img/book-banner-post-release.jpg)](https://mermaid-js.github.io/mermaid/landing/)
<!-- <Main description> -->
Mermaid is a Javascript based diagramming and charting tool that uses Markdown-inspired text definitions and a renderer to create and modify complex diagrams. The main purpose of Mermaid is to help documentation catch up with development.
Mermaid is a JavaScript based diagramming and charting tool that uses Markdown-inspired text definitions and a renderer to create and modify complex diagrams. The main purpose of Mermaid is to help documentation catch up with development.
> Doc-Rot is a Catch-22 that Mermaid helps to solve.
@@ -40,8 +40,14 @@ For a more detailed introduction to Mermaid and some of its more basic uses, loo
**Thanks to all involved, people committing pull requests, people answering questions and special thanks to Tyler Long who is helping me maintain the project 🙏**
In our release process we rely heavily on visual regression tests using [applitools](https://applitools.com/). Applitools is a great service which has been easy to use and integrate with our tests.
# Diagram Types
<a href="https://applitools.com/">
<svg width="170" height="32" viewBox="0 0 170 32" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="a" maskUnits="userSpaceOnUse" x="27" y="0" width="143" height="32"><path fill-rule="evenodd" clip-rule="evenodd" d="M27.732.227h141.391v31.19H27.733V.227z" fill="#fff"></path></mask><g mask="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M153.851 22.562l1.971-3.298c1.291 1.219 3.837 2.402 5.988 2.402 1.971 0 2.903-.753 2.903-1.829 0-2.832-10.253-.502-10.253-7.313 0-2.904 2.51-5.45 7.099-5.45 2.904 0 5.234 1.004 6.955 2.367l-1.829 3.226c-1.039-1.075-3.011-2.008-5.126-2.008-1.65 0-2.725.717-2.725 1.685 0 2.546 10.289.395 10.289 7.386 0 3.19-2.724 5.52-7.528 5.52-3.012 0-5.916-1.003-7.744-2.688zm-5.7 2.259h4.553V.908h-4.553v23.913zm-6.273-8.676c0-2.689-1.578-5.02-4.446-5.02-2.832 0-4.409 2.331-4.409 5.02 0 2.724 1.577 5.055 4.409 5.055 2.868 0 4.446-2.33 4.446-5.055zm-13.588 0c0-4.912 3.442-9.07 9.142-9.07 5.736 0 9.178 4.158 9.178 9.07 0 4.911-3.442 9.106-9.178 9.106-5.7 0-9.142-4.195-9.142-9.106zm-5.628 0c0-2.689-1.577-5.02-4.445-5.02-2.832 0-4.41 2.331-4.41 5.02 0 2.724 1.578 5.055 4.41 5.055 2.868 0 4.445-2.33 4.445-5.055zm-13.587 0c0-4.912 3.441-9.07 9.142-9.07 5.736 0 9.178 4.158 9.178 9.07 0 4.911-3.442 9.106-9.178 9.106-5.701 0-9.142-4.195-9.142-9.106zm-8.425 4.338v-8.999h-2.868v-3.98h2.868V2.773h4.553v4.733h3.514v3.979h-3.514v7.78c0 1.111.574 1.936 1.578 1.936.681 0 1.326-.251 1.577-.538l.968 3.478c-.681.609-1.9 1.11-3.8 1.11-3.191 0-4.876-1.648-4.876-4.767zm-8.962 4.338h4.553V7.505h-4.553V24.82zm-.43-21.905a2.685 2.685 0 012.688-2.69c1.506 0 2.725 1.184 2.725 2.69a2.724 2.724 0 01-2.725 2.724c-1.47 0-2.688-1.219-2.688-2.724zM84.482 24.82h4.553V.908h-4.553v23.913zm-6.165-8.676c0-2.976-1.793-5.02-4.41-5.02-1.47 0-3.119.825-3.908 1.973v6.094c.753 1.111 2.438 2.008 3.908 2.008 2.617 0 4.41-2.044 4.41-5.055zm-8.318 6.453v8.82h-4.553V7.504H70v2.187c1.327-1.685 3.227-2.618 5.342-2.618 4.446 0 7.672 3.299 7.672 9.07 0 5.773-3.226 9.107-7.672 9.107-2.043 0-3.907-.86-5.342-2.653zm-10.718-6.453c0-2.976-1.793-5.02-4.41-5.02-1.47 0-3.119.825-3.908 1.973v6.094c.753 1.111 2.438 2.008 3.908 2.008 2.617 0 4.41-2.044 4.41-5.055zm-8.318 6.453v8.82H46.41V7.504h4.553v2.187c1.327-1.685 3.227-2.618 5.342-2.618 4.446 0 7.672 3.299 7.672 9.07 0 5.773-3.226 9.107-7.672 9.107-2.043 0-3.908-.86-5.342-2.653zm-11.758-1.936V18.51c-.753-1.004-2.187-1.542-3.657-1.542-1.793 0-3.263.968-3.263 2.617 0 1.65 1.47 2.582 3.263 2.582 1.47 0 2.904-.502 3.657-1.506zm0 4.159v-1.829c-1.183 1.434-3.227 2.259-5.485 2.259-2.761 0-5.988-1.864-5.988-5.736 0-4.087 3.227-5.593 5.988-5.593 2.33 0 4.337.753 5.485 2.115V13.85c0-1.756-1.506-2.904-3.8-2.904-1.829 0-3.55.717-4.984 2.044L28.63 9.8c2.115-1.901 4.84-2.726 7.564-2.726 3.98 0 7.6 1.578 7.6 6.561v11.186h-4.588z" fill="#00A298"></path></g><path fill-rule="evenodd" clip-rule="evenodd" d="M14.934 16.177c0 1.287-.136 2.541-.391 3.752-1.666-1.039-3.87-2.288-6.777-3.752 2.907-1.465 5.11-2.714 6.777-3.753.255 1.211.39 2.466.39 3.753m4.6-7.666V4.486a78.064 78.064 0 01-4.336 3.567c-1.551-2.367-3.533-4.038-6.14-5.207C11.1 4.658 12.504 6.7 13.564 9.262 5.35 15.155 0 16.177 0 16.177s5.35 1.021 13.564 6.915c-1.06 2.563-2.463 4.603-4.507 6.415 2.607-1.169 4.589-2.84 6.14-5.207a77.978 77.978 0 014.336 3.568v-4.025s-.492-.82-2.846-2.492c.6-1.611.93-3.354.93-5.174a14.8 14.8 0 00-.93-5.174c2.354-1.673 2.846-2.492 2.846-2.492" fill="#00A298"></path></svg>
</a>
## Diagram Types
### [Flowchart](./flowchart.md?id=flowcharts-basic-syntax)
@@ -111,28 +117,20 @@ Class08 <--> C2: Cool label
![Class diagram](img/class.png)
### Git graph - :exclamation: experimental
```mmd
gitGraph:
options
{
"nodeSpacing": 150,
"nodeRadius": 10
}
end
commit
branch newbranch
checkout newbranch
commit
commit
checkout master
commit
commit
merge newbranch
### Git graph
```mermaid-example
gitGraph
commit
commit
branch develop
commit
commit
commit
checkout main
commit
commit
```
![Git graph](img/git.png)
### [Entity Relationship Diagram - :exclamation: experimental](./entityRelationshipDiagram.md)
@@ -161,7 +159,7 @@ journey
```
![Journey diagram](img/user-journey.png)
# Installation
## Installation
**In depth guides and examples can be found at [Getting Started](/n00b-gettingStarted) and [Usage](/usage).**
@@ -188,7 +186,7 @@ To Deploy Mermaid:
4. You can then add mermaid as a dev dependency using this command:
`yarn add --dev mermaid`
## [Mermaid API](./Setup.md):
### [Mermaid API](./Setup.md):
**To deploy mermaid without a bundler, one can insert a `script` tag with an absolute address and a `mermaidAPI` call into the HTML like so:**
@@ -197,11 +195,11 @@ To Deploy Mermaid:
<script>mermaid.initialize({startOnLoad:true});
</script>
```
**Doing so will command the mermaid parser to look for the `<div>` tags with `class="mermaid"`. From these tags mermaid will try to read the diagram/chart definitions and render them into svg charts.**
**Doing so will command the mermaid parser to look for the `<div>` tags with `class="mermaid"`. From these tags mermaid will try to read the diagram/chart definitions and render them into SVG charts.**
**Examples can be found at** [Other examples](/examples)
# Sibling projects
## Sibling projects
- [Mermaid Live Editor](https://github.com/mermaid-js/mermaid-live-editor)
- [Mermaid CLI](https://github.com/mermaid-js/mermaid-cli)
@@ -279,9 +277,9 @@ Detailed information about how to contribute can be found in the [contribution g
## Security and safe diagrams
For public sites, it can be precarious to retrieve text from users on the internet, storing that content for presentation in a browser at a later stage. The reason is that the user content can contain embedded malicious scripts that will run when the data is presented. For Mermaid this is a risk, specially as mermaid diagrams contain many characters that are used in html which makes the standard sanitation unusable as it also breaks the diagrams. We still make an effort to sanitise the incoming code and keep refining the process but it is hard to guarantee that there are no loop holes.
For public sites, it can be precarious to retrieve text from users on the internet, storing that content for presentation in a browser at a later stage. The reason is that the user content can contain embedded malicious scripts that will run when the data is presented. For Mermaid this is a risk, specially as mermaid diagrams contain many characters that are used in html which makes the standard sanitation unusable as it also breaks the diagrams. We still make an effort to sanitise the incoming code and keep refining the process but it is hard to guarantee that there are no loop holes.
As an extra level of security for sites with external users we are happy to introduce a new security level in which the diagram is rendered in a sandboxed iframe preventing javascript in the code from being executed. This is a great step forward for better security.
As an extra level of security for sites with external users we are happy to introduce a new security level in which the diagram is rendered in a sandboxed iframe preventing JavaScript in the code from being executed. This is a great step forward for better security.
*Unfortunately you can not have a cake and eat it at the same time which in this case means that some of the interactive functionality gets blocked along with the possible malicious code.*

View File

@@ -756,19 +756,6 @@ available space if not the absolute space required is used.
Default value: true
## useMaxWidth
| Parameter | Description | Type | Required | Values |
| ----------- | ----------- | ------- | -------- | ----------- |
| useMaxWidth | See notes | boolean | 4 | true, false |
**Notes:**
When this flag is set the height and width is set to 100% and is then scaling with the
available space if not the absolute space required is used.
Default value: true
## defaultRenderer
| Parameter | Description | Type | Required | Values |
@@ -831,13 +818,13 @@ Default value: 'TB'
### entityPadding
| Parameter | Description | Type | Required | Values |
| ------------- | ----------------------------------------------------------- | ------- | -------- | ------------------ |
| entityPadding | Minimum internal padding betweentext in box and box borders | Integer | 4 | Any Positive Value |
| Parameter | Description | Type | Required | Values |
| ------------- | ------------------------------------------------------------ | ------- | -------- | ------------------ |
| entityPadding | Minimum internal padding between text in box and box borders | Integer | 4 | Any Positive Value |
**Notes:**
The minimum internal padding betweentext in an entity box and the enclosing box borders,
The minimum internal padding between text in an entity box and the enclosing box borders,
expressed in pixels.
Default value: 15
@@ -915,6 +902,81 @@ available space. If set to false, the diagram reserves its absolute width.
Default value: true
## c4
The object containing configurations specific for c4 diagrams
### diagramMarginX
| Parameter | Description | Type | Required | Values |
| -------------- | ---------------------------------------------- | ------- | -------- | ------------------ |
| diagramMarginX | Margin to the right and left of the c4 diagram | Integer | Required | Any Positive Value |
**Notes:** Default value: 50
### diagramMarginY
| Parameter | Description | Type | Required | Values |
| -------------- | ------------------------------------------- | ------- | -------- | ------------------ |
| diagramMarginY | Margin to the over and under the c4 diagram | Integer | Required | Any Positive Value |
**Notes:** Default value: 10
### c4ShapeMargin
| Parameter | Description | Type | Required | Values |
| ----------- | --------------------- | ------- | -------- | ------------------ |
| shapeMargin | Margin between shapes | Integer | Required | Any Positive Value |
**Notes:** Default value: 50
### width
| Parameter | Description | Type | Required | Values |
| --------- | --------------------- | ------- | -------- | ------------------ |
| width | Width of person boxes | Integer | Required | Any Positive Value |
**Notes:** Default value: 216
### height
| Parameter | Description | Type | Required | Values |
| --------- | ---------------------- | ------- | -------- | ------------------ |
| height | Height of person boxes | Integer | Required | Any Positive Value |
**Notes:** Default value: 60
### boxMargin
| Parameter | Description | Type | Required | Values |
| --------- | ------------------------ | ------- | -------- | ------------------ |
| boxMargin | Margin around loop boxes | Integer | Required | Any Positive Value |
**Notes:** Default value: 10
### useMaxWidth
| Parameter | Description | Type | Required | Values |
| ----------- | ----------- | ------- | -------- | ----------- |
| useMaxWidth | See Notes | boolean | Required | true, false |
**Notes:** When this flag is set to true, the height and width is set to 100% and is then
scaling with the available space. If set to false, the absolute space required is used.
Default value: true
### wrap
This sets the auto-wrap state for the diagram
**Notes:** Default value: true.
### wrapPadding
This sets the auto-wrap padding for the diagram (sides only)
**Notes:** Default value: 0.
## setSiteConfig
## setSiteConfig
@@ -1017,9 +1079,9 @@ Pushes in a directive to the configuration
## conf
| Parameter | Description | Type | Required | Values |
| --------- | ------------------------------------------------------------- | ---------- | -------- | -------------------------------------------- |
| conf | base set of values, which currentConfig coul be **reset** to. | Dictionary | Required | Any Values, with respect to the secure Array |
| Parameter | Description | Type | Required | Values |
| --------- | -------------------------------------------------------------- | ---------- | -------- | -------------------------------------------- |
| conf | base set of values, which currentConfig could be **reset** to. | Dictionary | Required | Any Values, with respect to the secure Array |
**Notes**: (default: current siteConfig ) (optional, default `getSiteConfig()`)

View File

@@ -71,4 +71,4 @@ graph LR;
**Output**
![image](img/python-mermaid-integration.png)
![Example graph of the Python integration](img/python-mermaid-integration.png)

View File

@@ -14,6 +14,8 @@
- [Gantt](gantt.md)
- [Pie Chart](pie.md)
- [Requirement Diagram](requirementDiagram.md)
- [Gitgraph (Git) Diagram 🔥](gitgraph.md)
- [C4C Diagram (Context) Diagram 🦺⚠️](c4c.md)
- [Other Examples](examples.md)
- ⚙️ Deployment and Configuration

Some files were not shown because too many files have changed in this diff Show More