mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
getting there
This commit is contained in:
parent
3f6296b619
commit
bb2dd2f5f3
8
.ackrc
8
.ackrc
@ -1,4 +1,4 @@
|
||||
--ignore-dir=dist
|
||||
--ignore-file=match:/^yarn\.lock$/
|
||||
--ignore-file=match:/^yarn-error\.log$/
|
||||
--ignore-dir=coverage
|
||||
--ignore-dir=dist
|
||||
--ignore-file=match:/^yarn\.lock$/
|
||||
--ignore-file=match:/^yarn-error\.log$/
|
||||
--ignore-dir=coverage
|
||||
|
5
.commitlintrc.json
Normal file
5
.commitlintrc.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"@commitlint/config-conventional"
|
||||
]
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
indent_size = 4
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
indent_size = 4
|
||||
|
@ -1 +1,2 @@
|
||||
**/*.spec.js
|
||||
dist/**
|
||||
.github/**
|
||||
|
@ -2,19 +2,37 @@
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"jest/globals": true,
|
||||
"node": true
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"parser": "@babel/eslint-parser",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true,
|
||||
"jsx": true
|
||||
},
|
||||
"sourceType": "module"
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true,
|
||||
"jsx": true
|
||||
},
|
||||
"sourceType": "module"
|
||||
},
|
||||
"extends": ["prettier", "eslint:recommended"],
|
||||
"plugins": ["prettier"],
|
||||
"extends": ["eslint:recommended", "plugin:jsdoc/recommended", "plugin:markdown/recommended", "plugin:prettier/recommended"],
|
||||
"plugins": ["html", "jest", "jsdoc", "prettier"],
|
||||
"rules": {
|
||||
"prettier/prettier": ["error"]
|
||||
}
|
||||
"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-empty": ["error", { "allowEmptyCatch": true }]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": "./**/*.html",
|
||||
"rules": {
|
||||
"no-undef": "off",
|
||||
"jsdoc/require-jsdoc": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
24
.github/FUNDING.yml
vendored
24
.github/FUNDING.yml
vendored
@ -1,12 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [knsv]
|
||||
#patreon: # Replace with a single Patreon username
|
||||
#open_collective: # Replace with a single Open Collective username
|
||||
#ko_fi: # Replace with a single Ko-fi username
|
||||
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
#liberapay: # Replace with a single Liberapay username
|
||||
#issuehunt: # Replace with a single IssueHunt username
|
||||
#otechie: # Replace with a single Otechie username
|
||||
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [knsv]
|
||||
#patreon: # Replace with a single Patreon username
|
||||
#open_collective: # Replace with a single Open Collective username
|
||||
#ko_fi: # Replace with a single Ko-fi username
|
||||
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
#liberapay: # Replace with a single Liberapay username
|
||||
#issuehunt: # Replace with a single IssueHunt username
|
||||
#otechie: # Replace with a single Otechie username
|
||||
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
|
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -23,6 +23,9 @@ A clear and concise description of what you expected to happen.
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Code Sample**
|
||||
If applicable, add the code sample or a link to the [live editor](https://mermaid-js.github.io/mermaid-live-editor).
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
|
40
.github/ISSUE_TEMPLATE/feature_request.md
vendored
40
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,20 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: 'Status: Triage, Type: Enhancement'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: 'Status: Triage, Type: Enhancement'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
30
.github/ISSUE_TEMPLATE/question.md
vendored
30
.github/ISSUE_TEMPLATE/question.md
vendored
@ -1,15 +1,15 @@
|
||||
---
|
||||
name: Question
|
||||
about: Get some help from the community.
|
||||
title: ''
|
||||
labels: 'Help wanted!, Type: Other'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Help us help you!
|
||||
You want an answer. Here are some ways to get it quicker:
|
||||
* Use a clear and concise title.
|
||||
* Try to pose a clear and concise question.
|
||||
* Include as much, or as little, code as necessary.
|
||||
* Don't be shy to give us some screenshots, if it helps!
|
||||
---
|
||||
name: Question
|
||||
about: Get some help from the community.
|
||||
title: ''
|
||||
labels: 'Help wanted!, Type: Other'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Help us help you!
|
||||
You want an answer. Here are some ways to get it quicker:
|
||||
* Use a clear and concise title.
|
||||
* Try to pose a clear and concise question.
|
||||
* Include as much, or as little, code as necessary.
|
||||
* Don't be shy to give us some screenshots, if it helps!
|
||||
|
17
.github/dependabot.yml
vendored
Normal file
17
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
open-pull-requests-limit: 10
|
||||
directory: /
|
||||
target-branch: develop
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
time: "07:00"
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
target-branch: develop
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
time: "07:00"
|
26
.github/pull_request_template.md
vendored
26
.github/pull_request_template.md
vendored
@ -1,13 +1,13 @@
|
||||
## :bookmark_tabs: Summary
|
||||
Brief description about the content of your PR.
|
||||
|
||||
Resolves #<your issue id here>
|
||||
|
||||
## :straight_ruler: Design Decisions
|
||||
Describe the way your implementation works or what design decisions you made if applicable.
|
||||
|
||||
### :clipboard: Tasks
|
||||
Make sure you
|
||||
- [ ] :book: have read the [contribution guidelines](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md)
|
||||
- [ ] :computer: have added unit/e2e tests (if appropriate)
|
||||
- [ ] :bookmark: targeted `develop` branch
|
||||
## :bookmark_tabs: Summary
|
||||
Brief description about the content of your PR.
|
||||
|
||||
Resolves #<your issue id here>
|
||||
|
||||
## :straight_ruler: Design Decisions
|
||||
Describe the way your implementation works or what design decisions you made if applicable.
|
||||
|
||||
### :clipboard: Tasks
|
||||
Make sure you
|
||||
- [ ] :book: have read the [contribution guidelines](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md)
|
||||
- [ ] :computer: have added unit/e2e tests (if appropriate)
|
||||
- [ ] :bookmark: targeted `develop` branch
|
||||
|
50
.github/release-drafter.yml
vendored
50
.github/release-drafter.yml
vendored
@ -1,25 +1,25 @@
|
||||
name-template: '$NEXT_PATCH_VERSION'
|
||||
tag-template: '$NEXT_PATCH_VERSION'
|
||||
categories:
|
||||
- title: '🚀 Features'
|
||||
labels:
|
||||
- 'Type: Enhancement'
|
||||
- title: '🐛 Bug Fixes'
|
||||
labels:
|
||||
- 'Type: Bug / Error'
|
||||
- title: '🧰 Maintenance'
|
||||
label: 'Type: Other'
|
||||
change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
|
||||
sort-by: title
|
||||
sort-direction: ascending
|
||||
branches:
|
||||
- develop
|
||||
exclude-labels:
|
||||
- 'Skip changelog'
|
||||
no-changes-template: 'This release contains minor changes and bugfixes.'
|
||||
template: |
|
||||
# Release Notes
|
||||
|
||||
$CHANGES
|
||||
|
||||
🎉 **Thanks to all contributors helping with this release!** 🎉
|
||||
name-template: '$NEXT_PATCH_VERSION'
|
||||
tag-template: '$NEXT_PATCH_VERSION'
|
||||
categories:
|
||||
- title: '🚀 Features'
|
||||
labels:
|
||||
- 'Type: Enhancement'
|
||||
- title: '🐛 Bug Fixes'
|
||||
labels:
|
||||
- 'Type: Bug / Error'
|
||||
- title: '🧰 Maintenance'
|
||||
label: 'Type: Other'
|
||||
change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
|
||||
sort-by: title
|
||||
sort-direction: ascending
|
||||
branches:
|
||||
- develop
|
||||
exclude-labels:
|
||||
- 'Skip changelog'
|
||||
no-changes-template: 'This release contains minor changes and bugfixes.'
|
||||
template: |
|
||||
# Release Notes
|
||||
|
||||
$CHANGES
|
||||
|
||||
🎉 **Thanks to all contributors helping with this release!** 🎉
|
||||
|
38
.github/stale.yml
vendored
38
.github/stale.yml
vendored
@ -1,19 +1,19 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 60
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 14
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- Retained
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: Inactive
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
If you are still interested in this issue and it is still relevant you can comment to revive it.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: >
|
||||
This issue has been been automatically closed due to a lack of activity.
|
||||
This is done to maintain a clean list of issues that the community is interested in developing.
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 60
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 14
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- Retained
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: Inactive
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
If you are still interested in this issue and it is still relevant you can comment to revive it.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: >
|
||||
This issue has been been automatically closed due to a lack of activity.
|
||||
This is done to maintain a clean list of issues that the community is interested in developing.
|
||||
|
18
.github/workflows/build.yml
vendored
18
.github/workflows/build.yml
vendored
@ -7,27 +7,21 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x, 12.x]
|
||||
node-version: [16.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
cache: yarn
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install Yarn
|
||||
run: npm i yarn --global
|
||||
|
||||
- name: Cache Node Modules
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: .cache
|
||||
key: ${{ runner.OS }}-build-${{ hashFiles('**/yarn.lock') }}
|
||||
|
||||
- name: Install Packages
|
||||
run: |
|
||||
yarn config set cache-folder $GITHUB_WORKSPACE/.cache/yarn
|
||||
yarn install --frozen-lockfile
|
||||
env:
|
||||
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
||||
@ -36,7 +30,7 @@ jobs:
|
||||
run: yarn build
|
||||
|
||||
- name: Upload Build as Artifact
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: dist
|
||||
path: dist
|
||||
@ -61,4 +55,4 @@ jobs:
|
||||
# uses: coverallsapp/github-action@master
|
||||
# with:
|
||||
# github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# parallel-finished: true
|
||||
# parallel-finished: true
|
||||
|
38
.github/workflows/checks
vendored
38
.github/workflows/checks
vendored
@ -1,19 +1,19 @@
|
||||
on: [push]
|
||||
|
||||
name: Static analysis
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
name: check tests
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: testomatio/check-tests@stable
|
||||
with:
|
||||
framework: cypress
|
||||
tests: "./cypress/integration/**/**.spec.js"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
has-tests-label: true
|
||||
|
||||
on: [push]
|
||||
|
||||
name: Static analysis
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
name: check tests
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: testomatio/check-tests@stable
|
||||
with:
|
||||
framework: cypress
|
||||
tests: "./cypress/integration/**/**.spec.js"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
has-tests-label: true
|
||||
|
||||
|
52
.github/workflows/e2e.yml
vendored
Normal file
52
.github/workflows/e2e.yml
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
name: E2E
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
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 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
|
4
.github/workflows/issue-triage.yml
vendored
4
.github/workflows/issue-triage.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: andymckay/labeler@1.0
|
||||
- uses: andymckay/labeler@1.0.4
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
labels: "Status: Triage"
|
||||
add-labels: "Status: Triage"
|
||||
|
13
.github/workflows/pr-labeler-config-validator.yml
vendored
Normal file
13
.github/workflows/pr-labeler-config-validator.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
name: Validate PR Labeler Configuration
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
pr-labeler:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v2.3.4
|
||||
- name: Validate Configuration
|
||||
uses: Yash-Singh1/pr-labeler-config-validator@releases/v0.0.3
|
||||
with:
|
||||
configuration-path: .github/pr-labeler.yml
|
2
.github/workflows/pr-labeler.yml
vendored
2
.github/workflows/pr-labeler.yml
vendored
@ -1,6 +1,6 @@
|
||||
name: Apply labels to PR
|
||||
on:
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
|
2
.github/workflows/release-draft.yml
vendored
2
.github/workflows/release-draft.yml
vendored
@ -10,6 +10,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Draft Release
|
||||
uses: toolmantim/release-drafter@v5.2.0
|
||||
uses: toolmantim/release-drafter@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
@ -9,11 +9,11 @@ jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 10.x
|
||||
node-version: 16.x
|
||||
- name: Install Yarn
|
||||
run: npm i yarn --global
|
||||
|
||||
@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
PREVIEW_VERSION=$(git rev-list --count --first-parent HEAD)
|
||||
PREVIEW_VERSION=8
|
||||
VERSION=$(echo ${{github.ref}} | tail -c +20)-preview.$PREVIEW_VERSION
|
||||
echo $VERSION
|
||||
npm version --no-git-tag-version --allow-same-version $VERSION
|
||||
|
6
.github/workflows/release-publish.yml
vendored
6
.github/workflows/release-publish.yml
vendored
@ -8,13 +8,13 @@ jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- uses: fregante/setup-git-user@v1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 10.x
|
||||
node-version: 16.x
|
||||
- name: Install Yarn
|
||||
run: npm i yarn --global
|
||||
|
||||
|
26
.github/workflows/unlock-reopened-issues.yml
vendored
26
.github/workflows/unlock-reopened-issues.yml
vendored
@ -1,13 +1,13 @@
|
||||
name: Unlock reopened issue
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [reopened]
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Dunning-Kruger/unlock-issues@v1
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
name: Unlock reopened issue
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [reopened]
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Dunning-Kruger/unlock-issues@v1
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
18
.github/workflows/update-browserlist.yml
vendored
Normal file
18
.github/workflows/update-browserlist.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
name: Update Browserslist
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 7 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: npx browserslist@latest --update-db
|
||||
- name: Commit changes
|
||||
uses: EndBug/add-and-commit@v8.0.1
|
||||
with:
|
||||
author_name: ${{ github.actor }}
|
||||
author_email: ${{ github.actor }}@users.noreply.github.com
|
||||
message: 'chore: update browsers list'
|
7
.gitignore
vendored
7
.gitignore
vendored
@ -4,16 +4,14 @@ node_modules/
|
||||
coverage/
|
||||
.idea/
|
||||
|
||||
dist
|
||||
|
||||
yarn-error.log
|
||||
.npmrc
|
||||
token
|
||||
|
||||
package-lock.json
|
||||
|
||||
dist/classTest.html
|
||||
|
||||
dist/sequenceTest.html
|
||||
|
||||
.vscode/
|
||||
cypress/platform/current.html
|
||||
cypress/platform/experimental.html
|
||||
@ -21,3 +19,4 @@ local/
|
||||
|
||||
_site
|
||||
Gemfile.lock
|
||||
/.vs
|
||||
|
4
.husky/commit-msg
Normal file
4
.husky/commit-msg
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx --no-install commitlint --edit $1
|
4
.husky/pre-commit
Normal file
4
.husky/pre-commit
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
yarn pre-commit
|
5
.lintstagedrc.json
Normal file
5
.lintstagedrc.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"*.{js,html,md}": [
|
||||
"yarn lint:fix"
|
||||
]
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
version: 1
|
||||
version: 2
|
||||
snapshot:
|
||||
widths: [1280]
|
||||
widths:
|
||||
- 1280
|
||||
discovery:
|
||||
disable-cache: true
|
||||
|
8
.prettierrc.json
Normal file
8
.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"endOfLine": "auto",
|
||||
"plugins": [
|
||||
"prettier-plugin-jsdoc"
|
||||
],
|
||||
"printWidth": 100,
|
||||
"singleQuote": true
|
||||
}
|
@ -1,22 +1,22 @@
|
||||
{
|
||||
"ecmaVersion": 6,
|
||||
"libs": [
|
||||
"browser"
|
||||
],
|
||||
"loadEagerly": [
|
||||
"path/to/your/js/**/*.js"
|
||||
],
|
||||
"dontLoad": [
|
||||
"node_modules/**",
|
||||
"path/to/your/js/**/*.js"
|
||||
],
|
||||
"plugins": {
|
||||
"modules": {},
|
||||
"es_modules": {},
|
||||
"node": {},
|
||||
"doc_comment": {
|
||||
"fullDocs": true,
|
||||
"strong": true
|
||||
}
|
||||
}
|
||||
{
|
||||
"ecmaVersion": 6,
|
||||
"libs": [
|
||||
"browser"
|
||||
],
|
||||
"loadEagerly": [
|
||||
"path/to/your/js/**/*.js"
|
||||
],
|
||||
"dontLoad": [
|
||||
"node_modules/**",
|
||||
"path/to/your/js/**/*.js"
|
||||
],
|
||||
"plugins": {
|
||||
"modules": {},
|
||||
"es_modules": {},
|
||||
"node": {},
|
||||
"doc_comment": {
|
||||
"fullDocs": true,
|
||||
"strong": true
|
||||
}
|
||||
}
|
||||
}
|
25
.webpack/loaders/jison.js
Normal file
25
.webpack/loaders/jison.js
Normal file
@ -0,0 +1,25 @@
|
||||
const { Generator } = require('jison');
|
||||
const validate = require('schema-utils');
|
||||
|
||||
const schema = {
|
||||
title: 'Jison Parser options',
|
||||
type: 'object',
|
||||
properties: {
|
||||
'token-stack': {
|
||||
type: 'boolean',
|
||||
},
|
||||
debug: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
module.exports = function jisonLoader(source) {
|
||||
const options = this.getOptions();
|
||||
(validate.validate || validate)(schema, options, {
|
||||
name: 'Jison Loader',
|
||||
baseDataPath: 'options',
|
||||
});
|
||||
return new Generator(source, options).generate();
|
||||
};
|
45
.webpack/webpack.config.babel.js
Normal file
45
.webpack/webpack.config.babel.js
Normal file
@ -0,0 +1,45 @@
|
||||
import { merge, mergeWithCustomize, customizeObject } from 'webpack-merge';
|
||||
import nodeExternals from 'webpack-node-externals';
|
||||
import baseConfig from './webpack.config.base';
|
||||
|
||||
export default (_env, args) => {
|
||||
switch (args.mode) {
|
||||
case 'development':
|
||||
return [
|
||||
baseConfig,
|
||||
merge(baseConfig, {
|
||||
externals: [nodeExternals()],
|
||||
output: {
|
||||
filename: '[name].core.js',
|
||||
},
|
||||
}),
|
||||
];
|
||||
case 'production':
|
||||
return [
|
||||
// umd
|
||||
merge(baseConfig, {
|
||||
output: {
|
||||
filename: '[name].min.js',
|
||||
},
|
||||
}),
|
||||
// esm
|
||||
mergeWithCustomize({
|
||||
customizeObject: customizeObject({
|
||||
'output.library': 'replace',
|
||||
}),
|
||||
})(baseConfig, {
|
||||
experiments: {
|
||||
outputModule: true,
|
||||
},
|
||||
output: {
|
||||
library: {
|
||||
type: 'module',
|
||||
},
|
||||
filename: '[name].esm.min.mjs',
|
||||
},
|
||||
}),
|
||||
];
|
||||
default:
|
||||
throw new Error('No matching configuration was found!');
|
||||
}
|
||||
};
|
54
.webpack/webpack.config.base.js
Normal file
54
.webpack/webpack.config.base.js
Normal file
@ -0,0 +1,54 @@
|
||||
import path from 'path';
|
||||
|
||||
export const resolveRoot = (...relativePath) => path.resolve(__dirname, '..', ...relativePath);
|
||||
|
||||
export default {
|
||||
amd: false, // https://github.com/lodash/lodash/issues/3052
|
||||
target: 'web',
|
||||
entry: {
|
||||
mermaid: './src/mermaid.js',
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.wasm', '.mjs', '.js', '.json', '.jison'],
|
||||
fallback: {
|
||||
fs: false, // jison generated code requires 'fs'
|
||||
path: require.resolve('path-browserify'),
|
||||
},
|
||||
},
|
||||
output: {
|
||||
path: resolveRoot('./dist'),
|
||||
filename: '[name].js',
|
||||
library: {
|
||||
name: 'mermaid',
|
||||
type: 'umd',
|
||||
export: 'default',
|
||||
},
|
||||
globalObject: 'typeof self !== "undefined" ? self : this',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
include: [resolveRoot('./src'), resolveRoot('./node_modules/dagre-d3-renderer/lib')],
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
},
|
||||
},
|
||||
{
|
||||
// load scss to string
|
||||
test: /\.scss$/,
|
||||
use: ['css-to-string-loader', 'css-loader', 'sass-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.jison$/,
|
||||
use: {
|
||||
loader: path.resolve(__dirname, './loaders/jison.js'),
|
||||
options: {
|
||||
'token-stack': true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
devtool: 'source-map',
|
||||
};
|
37
.webpack/webpack.config.e2e.babel.js
Normal file
37
.webpack/webpack.config.e2e.babel.js
Normal file
@ -0,0 +1,37 @@
|
||||
import baseConfig, { resolveRoot } from './webpack.config.base';
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
export default merge(baseConfig, {
|
||||
mode: 'development',
|
||||
entry: {
|
||||
mermaid: './src/mermaid.js',
|
||||
e2e: './cypress/platform/viewer.js',
|
||||
'bundle-test': './cypress/platform/bundle-test.js',
|
||||
},
|
||||
output: {
|
||||
globalObject: 'window',
|
||||
},
|
||||
devServer: {
|
||||
compress: true,
|
||||
port: 9000,
|
||||
static: [
|
||||
{ directory: resolveRoot('cypress', 'platform') },
|
||||
{ directory: resolveRoot('dist') },
|
||||
{ directory: resolveRoot('demos') },
|
||||
],
|
||||
},
|
||||
externals: {
|
||||
mermaid: 'mermaid',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
1724
CHANGELOG.md
1724
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@ Here are a few things to know to get you started on the right path.
|
||||
We make all changes via pull requests. As we have many pull requests from developers new to mermaid, the current approach is to have *knsv, Knut Sveidqvist* as a main reviewer of changes and merging pull requests. More precisely like this:
|
||||
|
||||
* Large changes reviewed by knsv or other developer asked to review by knsv
|
||||
* Smaller low-risk changes like dependecies, documentation etc can be merged by active collaborators
|
||||
* Smaller low-risk changes like dependencies, documentation etc can be merged by active collaborators
|
||||
* documentation (updates to the docs folder is also allowed via direct commits)
|
||||
|
||||
To commit code, create a branch, let it start with the type like feature or bug followed by the issue number for reference and some describing text.
|
||||
@ -35,13 +35,13 @@ The documentation is written in Markdown, for more information about Markdown [s
|
||||
|
||||
If you want to preview the documentation site on your machine, you need to install `docsify-cli`:
|
||||
|
||||
```
|
||||
```sh
|
||||
$ npm i docsify-cli -g
|
||||
````
|
||||
```
|
||||
|
||||
If you are more familiar with Yarn, you can use the following command:
|
||||
|
||||
```
|
||||
```sh
|
||||
$ yarn global add docsify-cli
|
||||
```
|
||||
|
||||
@ -50,7 +50,7 @@ If the installation is successful, the command `docsify` will be available in yo
|
||||
|
||||
You can now run the following command to serve the documentation site:
|
||||
|
||||
```
|
||||
```sh
|
||||
$ docsify serve docs
|
||||
```
|
||||
|
||||
@ -85,7 +85,7 @@ The rendering tests are very straightforward to create. There is a function imgS
|
||||
When running in ci it will take a snapshot of the rendered diagram and compare it with the snapshot from last build and flag for review it if it differs.
|
||||
|
||||
This is what a rendering test looks like:
|
||||
```
|
||||
```javascript
|
||||
it('should render forks and joins', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 - 2018 Knut Sveidqvist
|
||||
Copyright (c) 2014 - 2021 Knut Sveidqvist
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
261
README.md
261
README.md
@ -1,15 +1,18 @@
|
||||
# mermaid [![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) [![This project is using Percy.io for visual regression testing.](https://percy.io/static/images/percy-badge.svg)](https://percy.io/Mermaid/mermaid)
|
||||
|
||||
English | [简体中文](./README.zh-CN.md)
|
||||
|
||||
![banner](./img/header.png)
|
||||
**Edit this Page** [![N|Solid](./docs/assets/img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/README.md)
|
||||
|
||||
: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 and special thanks to Tyler Long who is helping me maintain the project 🙏**
|
||||
**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>
|
||||
|
||||
## About
|
||||
|
||||
<!-- <Main description> -->
|
||||
<!-- <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.
|
||||
|
||||
> Doc-Rot is a Catch-22 that Mermaid helps to solve.
|
||||
@ -18,46 +21,43 @@ 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 cutting the time, effort and tooling that is required to create modifiable diagrams and charts, for smarter and more reusable content.
|
||||
The text definitions for Mermaid diagrams allows for it to be updated easily, it can also be made part of production scripts (and other pieces of code).
|
||||
So less time needs be spent on documenting, as a separate and laborious task. <br/>
|
||||
Even non-programmers can create diagrams through the [Mermaid Live Editor](https://github.com/mermaid-js/mermaid-live-editor).<br/>
|
||||
[Tutorials](./docs/getting-started/Tutorials.md) has video tutorials.
|
||||
Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/overview/integrations.md).
|
||||
So less time needs to be spent on documenting, as a separate and laborious task. <br/>
|
||||
Even non-programmers can create 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/overview/n00b-overview.md) and [Usage](./docs/getting-started/usage.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).
|
||||
|
||||
🌐 [CDN](https://unpkg.com/mermaid/) | 📖 [Documentation](https://mermaidjs.github.io) | 🙌 [Contribution](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md) | 📜 [Changelog](./docs/tutorials-and-community/CHANGELOG.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)
|
||||
|
||||
<!-- </Main description> -->
|
||||
|
||||
## Examples
|
||||
|
||||
__The following are some examples of the diagrams, charts and graphs that can be made using Mermaid and the Markdown-inspired text specific to it. Click here jump into the [text syntax](https://mermaid-js.github.io/mermaid/#/n00b-syntaxReference).__
|
||||
<table>
|
||||
<!-- <Flowchart> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>Flow</b></br>
|
||||
[<a href="http://mermaid-js.github.io/mermaid/#/flowchart">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBW0hhcmRdIC0tPnxUZXh0fCBCKFJvdW5kKVxuICAgIEIgLS0-IEN7RGVjaXNpb259XG4gICAgQyAtLT58T25lfCBEW1Jlc3VsdCAxXVxuICAgIEMgLS0-fFR3b3wgRVtSZXN1bHQgMl0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
graph TD
|
||||
|
||||
## Flowchart [<a href="http://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]
|
||||
C -->|Two| E[Result 2]
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-flow.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Flowchart> -->
|
||||
<!-- <Sequence> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>Sequence</b><br />
|
||||
[<a href="http://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>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
```
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[Hard] -->|Text| B(Round)
|
||||
B --> C{Decision}
|
||||
C -->|One| D[Result 1]
|
||||
C -->|Two| E[Result 2]
|
||||
```
|
||||
|
||||
|
||||
## Sequence diagram [<a href="http://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
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
@ -67,43 +67,48 @@ Note right of John: Rational thoughts!
|
||||
John-->>Alice: Great!
|
||||
John->>Bob: How about you?
|
||||
Bob-->>John: Jolly good!
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-sequence.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Sequence> -->
|
||||
<!-- <Gantt> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>Gantt</b><br />
|
||||
[<a href="http://mermaid-js.github.io/mermaid/#/gantt">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2FudHRcbnNlY3Rpb24gU2VjdGlvblxuQ29tcGxldGVkIDpkb25lLCAgICBkZXMxLCAyMDE0LTAxLTA2LDIwMTQtMDEtMDhcbkFjdGl2ZSAgICAgICAgOmFjdGl2ZSwgIGRlczIsIDIwMTQtMDEtMDcsIDNkXG5QYXJhbGxlbCAxICAgOiAgICAgICAgIGRlczMsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAyICAgOiAgICAgICAgIGRlczQsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAzICAgOiAgICAgICAgIGRlczUsIGFmdGVyIGRlczMsIDFkXG5QYXJhbGxlbCA0ICAgOiAgICAgICAgIGRlczYsIGFmdGVyIGRlczQsIDFkIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
```
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts!
|
||||
John-->>Alice: Great!
|
||||
John->>Bob: How about you?
|
||||
Bob-->>John: Jolly good!
|
||||
```
|
||||
|
||||
## Gantt chart [<a href="http://mermaid-js.github.io/mermaid/#/gantt">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2FudHRcbnNlY3Rpb24gU2VjdGlvblxuQ29tcGxldGVkIDpkb25lLCAgICBkZXMxLCAyMDE0LTAxLTA2LDIwMTQtMDEtMDhcbkFjdGl2ZSAgICAgICAgOmFjdGl2ZSwgIGRlczIsIDIwMTQtMDEtMDcsIDNkXG5QYXJhbGxlbCAxICAgOiAgICAgICAgIGRlczMsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAyICAgOiAgICAgICAgIGRlczQsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAzICAgOiAgICAgICAgIGRlczUsIGFmdGVyIGRlczMsIDFkXG5QYXJhbGxlbCA0ICAgOiAgICAgICAgIGRlczYsIGFmdGVyIGRlczQsIDFkIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
|
||||
```
|
||||
gantt
|
||||
section Section
|
||||
Completed :done, des1, 2014-01-06,2014-01-08
|
||||
Active :active, des2, 2014-01-07, 3d
|
||||
Parallel 1 : des3, after des1, 1d
|
||||
Parallel 2 : des4, after des1, 1d
|
||||
Parallel 3 : des5, after des3, 1d
|
||||
Parallel 4 : des6, after des4, 1d
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-gantt.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Gantt> -->
|
||||
<!-- <Class> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>Class</b><br />
|
||||
[<a href="http://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>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
section Section
|
||||
Completed :done, des1, 2014-01-06,2014-01-08
|
||||
Active :active, des2, 2014-01-07, 3d
|
||||
Parallel 1 : des3, after des1, 1d
|
||||
Parallel 2 : des4, after des1, 1d
|
||||
Parallel 3 : des5, after des3, 1d
|
||||
Parallel 4 : des6, after des4, 1d
|
||||
```
|
||||
```mermaid
|
||||
gantt
|
||||
section Section
|
||||
Completed :done, des1, 2014-01-06,2014-01-08
|
||||
Active :active, des2, 2014-01-07, 3d
|
||||
Parallel 1 : des3, after des1, 1d
|
||||
Parallel 2 : des4, after des1, 1d
|
||||
Parallel 3 : des5, after des3, 1d
|
||||
Parallel 4 : des6, after des4, 1d
|
||||
```
|
||||
|
||||
## Class diagram [<a href="http://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
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
<<interface>> Class01
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
<<Interface>> Class01
|
||||
Class09 --> C2 : Where am i?
|
||||
Class09 --* C3
|
||||
Class09 --|> Class07
|
||||
@ -113,23 +118,32 @@ Class01 : size()
|
||||
Class01 : int chimp
|
||||
Class01 : int gorilla
|
||||
class Class10 {
|
||||
<<service>>
|
||||
<<service>>
|
||||
int id
|
||||
size()
|
||||
}
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-class.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Class> -->
|
||||
<!-- <State> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>State</b><br />
|
||||
[<a href="http://mermaid-js.github.io/mermaid/#/stateDiagram">docs</a> - <a href="https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtLXYyXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQiLCJ0aGVtZVZhcmlhYmxlcyI6eyJiYWNrZ3JvdW5kIjoid2hpdGUiLCJwcmltYXJ5Q29sb3IiOiIjRUNFQ0ZGIiwic2Vjb25kYXJ5Q29sb3IiOiIjZmZmZmRlIiwidGVydGlhcnlDb2xvciI6ImhzbCg4MCwgMTAwJSwgOTYuMjc0NTA5ODAzOSUpIiwicHJpbWFyeUJvcmRlckNvbG9yIjoiaHNsKDI0MCwgNjAlLCA4Ni4yNzQ1MDk4MDM5JSkiLCJzZWNvbmRhcnlCb3JkZXJDb2xvciI6ImhzbCg2MCwgNjAlLCA4My41Mjk0MTE3NjQ3JSkiLCJ0ZXJ0aWFyeUJvcmRlckNvbG9yIjoiaHNsKDgwLCA2MCUsIDg2LjI3NDUwOTgwMzklKSIsInByaW1hcnlUZXh0Q29sb3IiOiIjMTMxMzAwIiwic2Vjb25kYXJ5VGV4dENvbG9yIjoiIzAwMDAyMSIsInRlcnRpYXJ5VGV4dENvbG9yIjoicmdiKDkuNTAwMDAwMDAwMSwgOS41MDAwMDAwMDAxLCA5LjUwMDAwMDAwMDEpIiwibGluZUNvbG9yIjoiIzMzMzMzMyIsInRleHRDb2xvciI6IiMzMzMiLCJtYWluQmtnIjoiI0VDRUNGRiIsInNlY29uZEJrZyI6IiNmZmZmZGUiLCJib3JkZXIxIjoiIzkzNzBEQiIsImJvcmRlcjIiOiIjYWFhYTMzIiwiYXJyb3doZWFkQ29sb3IiOiIjMzMzMzMzIiwiZm9udEZhbWlseSI6IlwidHJlYnVjaGV0IG1zXCIsIHZlcmRhbmEsIGFyaWFsIiwiZm9udFNpemUiOiIxNnB4IiwibGFiZWxCYWNrZ3JvdW5kIjoiI2U4ZThlOCIsIm5vZGVCa2ciOiIjRUNFQ0ZGIiwibm9kZUJvcmRlciI6IiM5MzcwREIiLCJjbHVzdGVyQmtnIjoiI2ZmZmZkZSIsImNsdXN0ZXJCb3JkZXIiOiIjYWFhYTMzIiwiZGVmYXVsdExpbmtDb2xvciI6IiMzMzMzMzMiLCJ0aXRsZUNvbG9yIjoiIzMzMyIsImVkZ2VMYWJlbEJhY2tncm91bmQiOiIjZThlOGU4IiwiYWN0b3JCb3JkZXIiOiJoc2woMjU5LjYyNjE2ODIyNDMsIDU5Ljc3NjUzNjMxMjglLCA4Ny45MDE5NjA3ODQzJSkiLCJhY3RvckJrZyI6IiNFQ0VDRkYiLCJhY3RvclRleHRDb2xvciI6ImJsYWNrIiwiYWN0b3JMaW5lQ29sb3IiOiJncmV5Iiwic2lnbmFsQ29sb3IiOiIjMzMzIiwic2lnbmFsVGV4dENvbG9yIjoiIzMzMyIsImxhYmVsQm94QmtnQ29sb3IiOiIjRUNFQ0ZGIiwibGFiZWxCb3hCb3JkZXJDb2xvciI6ImhzbCgyNTkuNjI2MTY4MjI0MywgNTkuNzc2NTM2MzEyOCUsIDg3LjkwMTk2MDc4NDMlKSIsImxhYmVsVGV4dENvbG9yIjoiYmxhY2siLCJsb29wVGV4dENvbG9yIjoiYmxhY2siLCJub3RlQm9yZGVyQ29sb3IiOiIjYWFhYTMzIiwibm90ZUJrZ0NvbG9yIjoiI2ZmZjVhZCIsIm5vdGVUZXh0Q29sb3IiOiJibGFjayIsImFjdGl2YXRpb25Cb3JkZXJDb2xvciI6IiM2NjYiLCJhY3RpdmF0aW9uQmtnQ29sb3IiOiIjZjRmNGY0Iiwic2VxdWVuY2VOdW1iZXJDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yIjoicmdiYSgxMDIsIDEwMiwgMjU1LCAwLjQ5KSIsImFsdFNlY3Rpb25Ca2dDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yMiI6IiNmZmY0MDAiLCJ0YXNrQm9yZGVyQ29sb3IiOiIjNTM0ZmJjIiwidGFza0JrZ0NvbG9yIjoiIzhhOTBkZCIsInRhc2tUZXh0TGlnaHRDb2xvciI6IndoaXRlIiwidGFza1RleHRDb2xvciI6IndoaXRlIiwidGFza1RleHREYXJrQ29sb3IiOiJibGFjayIsInRhc2tUZXh0T3V0c2lkZUNvbG9yIjoiYmxhY2siLCJ0YXNrVGV4dENsaWNrYWJsZUNvbG9yIjoiIzAwMzE2MyIsImFjdGl2ZVRhc2tCb3JkZXJDb2xvciI6IiM1MzRmYmMiLCJhY3RpdmVUYXNrQmtnQ29sb3IiOiIjYmZjN2ZmIiwiZ3JpZENvbG9yIjoibGlnaHRncmV5IiwiZG9uZVRhc2tCa2dDb2xvciI6ImxpZ2h0Z3JleSIsImRvbmVUYXNrQm9yZGVyQ29sb3IiOiJncmV5IiwiY3JpdEJvcmRlckNvbG9yIjoiI2ZmODg4OCIsImNyaXRCa2dDb2xvciI6InJlZCIsInRvZGF5TGluZUNvbG9yIjoicmVkIiwibGFiZWxDb2xvciI6ImJsYWNrIiwiZXJyb3JCa2dDb2xvciI6IiM1NTIyMjIiLCJlcnJvclRleHRDb2xvciI6IiM1NTIyMjIiLCJjbGFzc1RleHQiOiIjMTMxMzAwIiwiZmlsbFR5cGUwIjoiI0VDRUNGRiIsImZpbGxUeXBlMSI6IiNmZmZmZGUiLCJmaWxsVHlwZTIiOiJoc2woMzA0LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTMiOiJoc2woMTI0LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkiLCJmaWxsVHlwZTQiOiJoc2woMTc2LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTUiOiJoc2woLTQsIDEwMCUsIDkzLjUyOTQxMTc2NDclKSIsImZpbGxUeXBlNiI6ImhzbCg4LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTciOiJoc2woMTg4LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkifX0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
```
|
||||
```mermaid
|
||||
classDiagram
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
<<Interface>> Class01
|
||||
Class09 --> C2 : Where am i?
|
||||
Class09 --* C3
|
||||
Class09 --|> Class07
|
||||
Class07 : equals()
|
||||
Class07 : Object[] elementData
|
||||
Class01 : size()
|
||||
Class01 : int chimp
|
||||
Class01 : int gorilla
|
||||
class Class10 {
|
||||
<<service>>
|
||||
int id
|
||||
size()
|
||||
}
|
||||
```
|
||||
|
||||
## State diagram [<a href="http://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
|
||||
Still --> [*]
|
||||
@ -137,46 +151,36 @@ Still --> Moving
|
||||
Moving --> Still
|
||||
Moving --> Crash
|
||||
Crash --> [*]
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-state.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </State> -->
|
||||
<!-- <Pie> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>Pie</b><br />
|
||||
[<a href="http://mermaid-js.github.io/mermaid/#/pie">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoicGllXG5cIkRvZ3NcIiA6IDQyLjk2XG5cIkNhdHNcIiA6IDUwLjA1XG5cIlJhdHNcIiA6IDEwLjAxIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
```
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Still
|
||||
Still --> [*]
|
||||
Still --> Moving
|
||||
Moving --> Still
|
||||
Moving --> Crash
|
||||
Crash --> [*]
|
||||
```
|
||||
|
||||
### Pie chart [<a href="http://mermaid-js.github.io/mermaid/#/pie">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoicGllXG5cIkRvZ3NcIiA6IDQyLjk2XG5cIkNhdHNcIiA6IDUwLjA1XG5cIlJhdHNcIiA6IDEwLjAxIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
|
||||
```
|
||||
pie
|
||||
"Dogs" : 386
|
||||
"Cats" : 85
|
||||
"Rats" : 15
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-pie.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Pie> -->
|
||||
<!-- <Git> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>Git</b><br />
|
||||
[experimental - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2l0R3JhcGg6XG5vcHRpb25zXG57XG4gICAgXCJub2RlU3BhY2luZ1wiOiAxNTAsXG4gICAgXCJub2RlUmFkaXVzXCI6IDEwXG59XG5lbmRcbmNvbW1pdFxuYnJhbmNoIG5ld2JyYW5jaFxuY2hlY2tvdXQgbmV3YnJhbmNoXG5jb21taXRcbmNvbW1pdFxuY2hlY2tvdXQgbWFzdGVyXG5jb21taXRcbmNvbW1pdFxubWVyZ2UgbmV3YnJhbmNoXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td colspan="2" align="center"><i>Coming soon!</i></td>
|
||||
</tr>
|
||||
<!-- </Git> -->
|
||||
<!-- <Journey> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>User Journey</b><br />
|
||||
[<a href="http://mermaid-js.github.io/mermaid/#/user-journey">docs</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td>
|
||||
<pre>
|
||||
```
|
||||
```mermaid
|
||||
pie
|
||||
"Dogs" : 386
|
||||
"Cats" : 85
|
||||
"Rats" : 15
|
||||
```
|
||||
|
||||
## Git graph [experimental - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2l0R3JhcGg6XG5vcHRpb25zXG57XG4gICAgXCJub2RlU3BhY2luZ1wiOiAxNTAsXG4gICAgXCJub2RlUmFkaXVzXCI6IDEwXG59XG5lbmRcbmNvbW1pdFxuYnJhbmNoIG5ld2JyYW5jaFxuY2hlY2tvdXQgbmV3YnJhbmNoXG5jb21taXRcbmNvbW1pdFxuY2hlY2tvdXQgbWFzdGVyXG5jb21taXRcbmNvbW1pdFxubWVyZ2UgbmV3YnJhbmNoXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
|
||||
|
||||
## User Journey diagram [<a href="http://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
|
||||
section Go to work
|
||||
@ -186,14 +190,18 @@ pie
|
||||
section Go home
|
||||
Go downstairs: 5: Me
|
||||
Sit down: 3: Me
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img alt="User Journey Diagram" src="img/gray-user-journey.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Journey> -->
|
||||
|
||||
</table>
|
||||
```
|
||||
```mermaid
|
||||
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: 3: Me
|
||||
```
|
||||
|
||||
## Related projects
|
||||
|
||||
@ -201,12 +209,15 @@ pie
|
||||
- [Live Editor](https://github.com/mermaid-js/mermaid-live-editor)
|
||||
- [HTTP Server](https://github.com/TomWright/mermaid-server)
|
||||
|
||||
## Contributors [![Help wanted](https://img.shields.io/github/labels/mermaid-js/mermaid/Help%20wanted!)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Help+wanted%21%22) [![Contributors](https://img.shields.io/github/contributors/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) [![Commits](https://img.shields.io/github/commit-activity/m/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors)
|
||||
## Contributors [![Good first issue](https://img.shields.io/github/labels/mermaid-js/mermaid/Good%20first%20issue%21)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%21%22) [![Contributors](https://img.shields.io/github/contributors/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) [![Commits](https://img.shields.io/github/commit-activity/m/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors)
|
||||
|
||||
Mermaid is a growing community and is always accepting new contributors. There's a lot of different ways to help out and we're always looking for extra hands! Look at [this issue](https://github.com/mermaid-js/mermaid/issues/866) if you want to know where to start helping out.
|
||||
|
||||
Detailed information about how to contribute can be found in the [contribution guide](CONTRIBUTING.md)
|
||||
|
||||
## Reporting vulnerabilities
|
||||
To report a vulnerability, please e-mail security@mermaid.live with a description of the issue, the steps you took to create the issue, affected versions, and if known, mitigations for the issue.
|
||||
|
||||
## Appreciation
|
||||
A quick note from Knut Sveidqvist:
|
||||
>*Many thanks to the [d3](http://d3js.org/) and [dagre-d3](https://github.com/cpettitt/dagre-d3) projects for providing the graphical layout and drawing libraries!*
|
||||
@ -217,4 +228,4 @@ A quick note from Knut Sveidqvist:
|
||||
|
||||
---
|
||||
|
||||
*Mermaid was created by Knut Sveidqvist for easier documentation.*
|
||||
*Mermaid was created by Knut Sveidqvist for easier documentation.*
|
224
README.zh-CN.md
Normal file
224
README.zh-CN.md
Normal file
@ -0,0 +1,224 @@
|
||||
# mermaid [![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) [![This project is using Percy.io for visual regression testing.](https://percy.io/static/images/percy-badge.svg)](https://percy.io/Mermaid/mermaid)
|
||||
|
||||
[English](./README.md) | 简体中文
|
||||
|
||||
![banner](./img/header.png)
|
||||
|
||||
: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>
|
||||
|
||||
## 关于 Mermaid
|
||||
|
||||
<!-- <Main description> -->
|
||||
Mermaid 是一个基于 Javascript 的图表绘制工具,通过解析类 Markdown 的文本语法来实现图表的创建和动态修改。Mermaid 诞生的主要目的是让文档的更新能够及时跟上开发进度。
|
||||
|
||||
> Mermaid 致力于解决 Doc-Rot 这个令人头疼的问题。
|
||||
|
||||
绘图和编写文档花费了开发者宝贵的开发时间,而且随着业务的变更,它很快就会过期。 但是如果缺少了图表或文档,对于生产力和团队新人的业务学习都会产生巨大的阻碍。 <br/>
|
||||
Mermaid 通过减少创建可修改的图表所需要的时间、精力和工具来解决这一难题,从而提高了内容的智能化和可重用性。 作为一个基于文本的绘图工具, Mermaid 天生就易于维护和更新,它也可以作为生产脚本(或其他代码)的一部分,使得文档编写变得更加简单。 有了它之后,开发者可以从维护文档这个与开发割离且麻烦的任务中解放出来。 <br/>
|
||||
即使是从未接触过编程的非专业人员也可以通过 [Mermaid Live Editor](https://mermaid-js.github.io/mermaid-live-editor/)来创建图表。<br/>
|
||||
你可以访问 [教程](./docs/Tutorials.md) 来查看 Live Editor 的视频教程。
|
||||
U也可以查看 [Mermaid 的集成和使用](./docs/integrations.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。
|
||||
|
||||
如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/n00b-overview.md) and [用法](./docs/usage.md).
|
||||
|
||||
🌐 [CDN](https://unpkg.com/mermaid/) | 📖 [文档](https://mermaidjs.github.io) | 🙌 [贡献](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md) | 📜 [更新日志](./docs/CHANGELOG.md)
|
||||
|
||||
<!-- </Main description> -->
|
||||
|
||||
## 示例
|
||||
|
||||
__下面是一些使用 Mermaid 和类 Markdown 语法创建的图表示例。点击 [语法](https://mermaid-js.github.io/mermaid/#/n00b-syntaxReference) 查看详情__
|
||||
<table>
|
||||
<!-- <Flowchart> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>流程图</b></br>
|
||||
[<a href="http://mermaid-js.github.io/mermaid/#/flowchart">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBW0hhcmRdIC0tPnxUZXh0fCBCKFJvdW5kKVxuICAgIEIgLS0-IEN7RGVjaXNpb259XG4gICAgQyAtLT58T25lfCBEW1Jlc3VsdCAxXVxuICAgIEMgLS0-fFR3b3wgRVtSZXN1bHQgMl0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
flowchart TD
|
||||
A[Hard] -->|Text| B(Round)
|
||||
B --> C{Decision}
|
||||
C -->|One| D[Result 1]
|
||||
C -->|Two| E[Result 2]
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-flow.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Flowchart> -->
|
||||
<!-- <Sequence> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>时序图</b><br />
|
||||
[<a href="http://mermaid-js.github.io/mermaid/#/sequenceDiagram">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic2VxdWVuY2VEaWFncmFtXG5BbGljZS0-PkpvaG46IEhlbGxvIEpvaG4sIGhvdyBhcmUgeW91P1xubG9vcCBIZWFsdGhjaGVja1xuICAgIEpvaG4tPj5Kb2huOiBGaWdodCBhZ2FpbnN0IGh5cG9jaG9uZHJpYVxuZW5kXG5Ob3RlIHJpZ2h0IG9mIEpvaG46IFJhdGlvbmFsIHRob3VnaHRzIVxuSm9obi0tPj5BbGljZTogR3JlYXQhXG5Kb2huLT4-Qm9iOiBIb3cgYWJvdXQgeW91P1xuQm9iLS0-PkpvaG46IEpvbGx5IGdvb2QhIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
sequenceDiagram
|
||||
Alice->>John: Hello John, how are you?
|
||||
loop Healthcheck
|
||||
John->>John: Fight against hypochondria
|
||||
end
|
||||
Note right of John: Rational thoughts!
|
||||
John-->>Alice: Great!
|
||||
John->>Bob: How about you?
|
||||
Bob-->>John: Jolly good!
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-sequence.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Sequence> -->
|
||||
<!-- <Gantt> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>甘特图</b><br />
|
||||
[<a href="http://mermaid-js.github.io/mermaid/#/gantt">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2FudHRcbnNlY3Rpb24gU2VjdGlvblxuQ29tcGxldGVkIDpkb25lLCAgICBkZXMxLCAyMDE0LTAxLTA2LDIwMTQtMDEtMDhcbkFjdGl2ZSAgICAgICAgOmFjdGl2ZSwgIGRlczIsIDIwMTQtMDEtMDcsIDNkXG5QYXJhbGxlbCAxICAgOiAgICAgICAgIGRlczMsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAyICAgOiAgICAgICAgIGRlczQsIGFmdGVyIGRlczEsIDFkXG5QYXJhbGxlbCAzICAgOiAgICAgICAgIGRlczUsIGFmdGVyIGRlczMsIDFkXG5QYXJhbGxlbCA0ICAgOiAgICAgICAgIGRlczYsIGFmdGVyIGRlczQsIDFkIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
gantt
|
||||
section Section
|
||||
Completed :done, des1, 2014-01-06,2014-01-08
|
||||
Active :active, des2, 2014-01-07, 3d
|
||||
Parallel 1 : des3, after des1, 1d
|
||||
Parallel 2 : des4, after des1, 1d
|
||||
Parallel 3 : des5, after des3, 1d
|
||||
Parallel 4 : des6, after des4, 1d
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-gantt.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Gantt> -->
|
||||
<!-- <Class> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>类图</b><br />
|
||||
[<a href="http://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>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
classDiagram
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
<<interface>> Class01
|
||||
Class09 --> C2 : Where am i?
|
||||
Class09 --* C3
|
||||
Class09 --|> Class07
|
||||
Class07 : equals()
|
||||
Class07 : Object[] elementData
|
||||
Class01 : size()
|
||||
Class01 : int chimp
|
||||
Class01 : int gorilla
|
||||
class Class10 {
|
||||
<<service>>
|
||||
int id
|
||||
size()
|
||||
}
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-class.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Class> -->
|
||||
<!-- <State> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>状态图</b><br />
|
||||
[<a href="http://mermaid-js.github.io/mermaid/#/stateDiagram">文档</a> - <a href="https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtLXYyXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQiLCJ0aGVtZVZhcmlhYmxlcyI6eyJiYWNrZ3JvdW5kIjoid2hpdGUiLCJwcmltYXJ5Q29sb3IiOiIjRUNFQ0ZGIiwic2Vjb25kYXJ5Q29sb3IiOiIjZmZmZmRlIiwidGVydGlhcnlDb2xvciI6ImhzbCg4MCwgMTAwJSwgOTYuMjc0NTA5ODAzOSUpIiwicHJpbWFyeUJvcmRlckNvbG9yIjoiaHNsKDI0MCwgNjAlLCA4Ni4yNzQ1MDk4MDM5JSkiLCJzZWNvbmRhcnlCb3JkZXJDb2xvciI6ImhzbCg2MCwgNjAlLCA4My41Mjk0MTE3NjQ3JSkiLCJ0ZXJ0aWFyeUJvcmRlckNvbG9yIjoiaHNsKDgwLCA2MCUsIDg2LjI3NDUwOTgwMzklKSIsInByaW1hcnlUZXh0Q29sb3IiOiIjMTMxMzAwIiwic2Vjb25kYXJ5VGV4dENvbG9yIjoiIzAwMDAyMSIsInRlcnRpYXJ5VGV4dENvbG9yIjoicmdiKDkuNTAwMDAwMDAwMSwgOS41MDAwMDAwMDAxLCA5LjUwMDAwMDAwMDEpIiwibGluZUNvbG9yIjoiIzMzMzMzMyIsInRleHRDb2xvciI6IiMzMzMiLCJtYWluQmtnIjoiI0VDRUNGRiIsInNlY29uZEJrZyI6IiNmZmZmZGUiLCJib3JkZXIxIjoiIzkzNzBEQiIsImJvcmRlcjIiOiIjYWFhYTMzIiwiYXJyb3doZWFkQ29sb3IiOiIjMzMzMzMzIiwiZm9udEZhbWlseSI6IlwidHJlYnVjaGV0IG1zXCIsIHZlcmRhbmEsIGFyaWFsIiwiZm9udFNpemUiOiIxNnB4IiwibGFiZWxCYWNrZ3JvdW5kIjoiI2U4ZThlOCIsIm5vZGVCa2ciOiIjRUNFQ0ZGIiwibm9kZUJvcmRlciI6IiM5MzcwREIiLCJjbHVzdGVyQmtnIjoiI2ZmZmZkZSIsImNsdXN0ZXJCb3JkZXIiOiIjYWFhYTMzIiwiZGVmYXVsdExpbmtDb2xvciI6IiMzMzMzMzMiLCJ0aXRsZUNvbG9yIjoiIzMzMyIsImVkZ2VMYWJlbEJhY2tncm91bmQiOiIjZThlOGU4IiwiYWN0b3JCb3JkZXIiOiJoc2woMjU5LjYyNjE2ODIyNDMsIDU5Ljc3NjUzNjMxMjglLCA4Ny45MDE5NjA3ODQzJSkiLCJhY3RvckJrZyI6IiNFQ0VDRkYiLCJhY3RvclRleHRDb2xvciI6ImJsYWNrIiwiYWN0b3JMaW5lQ29sb3IiOiJncmV5Iiwic2lnbmFsQ29sb3IiOiIjMzMzIiwic2lnbmFsVGV4dENvbG9yIjoiIzMzMyIsImxhYmVsQm94QmtnQ29sb3IiOiIjRUNFQ0ZGIiwibGFiZWxCb3hCb3JkZXJDb2xvciI6ImhzbCgyNTkuNjI2MTY4MjI0MywgNTkuNzc2NTM2MzEyOCUsIDg3LjkwMTk2MDc4NDMlKSIsImxhYmVsVGV4dENvbG9yIjoiYmxhY2siLCJsb29wVGV4dENvbG9yIjoiYmxhY2siLCJub3RlQm9yZGVyQ29sb3IiOiIjYWFhYTMzIiwibm90ZUJrZ0NvbG9yIjoiI2ZmZjVhZCIsIm5vdGVUZXh0Q29sb3IiOiJibGFjayIsImFjdGl2YXRpb25Cb3JkZXJDb2xvciI6IiM2NjYiLCJhY3RpdmF0aW9uQmtnQ29sb3IiOiIjZjRmNGY0Iiwic2VxdWVuY2VOdW1iZXJDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yIjoicmdiYSgxMDIsIDEwMiwgMjU1LCAwLjQ5KSIsImFsdFNlY3Rpb25Ca2dDb2xvciI6IndoaXRlIiwic2VjdGlvbkJrZ0NvbG9yMiI6IiNmZmY0MDAiLCJ0YXNrQm9yZGVyQ29sb3IiOiIjNTM0ZmJjIiwidGFza0JrZ0NvbG9yIjoiIzhhOTBkZCIsInRhc2tUZXh0TGlnaHRDb2xvciI6IndoaXRlIiwidGFza1RleHRDb2xvciI6IndoaXRlIiwidGFza1RleHREYXJrQ29sb3IiOiJibGFjayIsInRhc2tUZXh0T3V0c2lkZUNvbG9yIjoiYmxhY2siLCJ0YXNrVGV4dENsaWNrYWJsZUNvbG9yIjoiIzAwMzE2MyIsImFjdGl2ZVRhc2tCb3JkZXJDb2xvciI6IiM1MzRmYmMiLCJhY3RpdmVUYXNrQmtnQ29sb3IiOiIjYmZjN2ZmIiwiZ3JpZENvbG9yIjoibGlnaHRncmV5IiwiZG9uZVRhc2tCa2dDb2xvciI6ImxpZ2h0Z3JleSIsImRvbmVUYXNrQm9yZGVyQ29sb3IiOiJncmV5IiwiY3JpdEJvcmRlckNvbG9yIjoiI2ZmODg4OCIsImNyaXRCa2dDb2xvciI6InJlZCIsInRvZGF5TGluZUNvbG9yIjoicmVkIiwibGFiZWxDb2xvciI6ImJsYWNrIiwiZXJyb3JCa2dDb2xvciI6IiM1NTIyMjIiLCJlcnJvclRleHRDb2xvciI6IiM1NTIyMjIiLCJjbGFzc1RleHQiOiIjMTMxMzAwIiwiZmlsbFR5cGUwIjoiI0VDRUNGRiIsImZpbGxUeXBlMSI6IiNmZmZmZGUiLCJmaWxsVHlwZTIiOiJoc2woMzA0LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTMiOiJoc2woMTI0LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkiLCJmaWxsVHlwZTQiOiJoc2woMTc2LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTUiOiJoc2woLTQsIDEwMCUsIDkzLjUyOTQxMTc2NDclKSIsImZpbGxUeXBlNiI6ImhzbCg4LCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSkiLCJmaWxsVHlwZTciOiJoc2woMTg4LCAxMDAlLCA5My41Mjk0MTE3NjQ3JSkifX0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
stateDiagram-v2
|
||||
[*] --> Still
|
||||
Still --> [*]
|
||||
Still --> Moving
|
||||
Moving --> Still
|
||||
Moving --> Crash
|
||||
Crash --> [*]
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-state.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </State> -->
|
||||
<!-- <Pie> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>饼图</b><br />
|
||||
[<a href="http://mermaid-js.github.io/mermaid/#/pie">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoicGllXG5cIkRvZ3NcIiA6IDQyLjk2XG5cIkNhdHNcIiA6IDUwLjA1XG5cIlJhdHNcIiA6IDEwLjAxIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
pie
|
||||
"Dogs" : 386
|
||||
"Cats" : 85
|
||||
"Rats" : 15
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img src="https://raw.githubusercontent.com/mermaid-js/mermaid/master/img/gray-pie.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Pie> -->
|
||||
<!-- <Git> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>Git图</b><br />
|
||||
[实验特性 - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ2l0R3JhcGg6XG5vcHRpb25zXG57XG4gICAgXCJub2RlU3BhY2luZ1wiOiAxNTAsXG4gICAgXCJub2RlUmFkaXVzXCI6IDEwXG59XG5lbmRcbmNvbW1pdFxuYnJhbmNoIG5ld2JyYW5jaFxuY2hlY2tvdXQgbmV3YnJhbmNoXG5jb21taXRcbmNvbW1pdFxuY2hlY2tvdXQgbWFzdGVyXG5jb21taXRcbmNvbW1pdFxubWVyZ2UgbmV3YnJhbmNoXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td colspan="2" align="center"><i>敬请期待!</i></td>
|
||||
</tr>
|
||||
<!-- </Git> -->
|
||||
<!-- <Journey> -->
|
||||
<tr><td colspan=2 align="center">
|
||||
<b>用户体验旅程图</b><br />
|
||||
[<a href="http://mermaid-js.github.io/mermaid/#/user-journey">文档</a> - <a href="https://mermaidjs.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtXG4gICAgWypdIC0tPiBTdGlsbFxuICAgIFN0aWxsIC0tPiBbKl1cbiAgICBTdGlsbCAtLT4gTW92aW5nXG4gICAgTW92aW5nIC0tPiBTdGlsbFxuICAgIE1vdmluZyAtLT4gQ3Jhc2hcbiAgICBDcmFzaCAtLT4gWypdIiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifX0">live editor</a>]
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td>
|
||||
<pre>
|
||||
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: 3: Me
|
||||
</pre></td>
|
||||
<td align="center">
|
||||
<img alt="User Journey Diagram" src="img/gray-user-journey.png" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- </Journey> -->
|
||||
|
||||
</table>
|
||||
|
||||
## 相关项目
|
||||
|
||||
- [Command Line Interface](https://github.com/mermaid-js/mermaid-cli)
|
||||
- [Live Editor](https://github.com/mermaid-js/mermaid-live-editor)
|
||||
- [HTTP Server](https://github.com/TomWright/mermaid-server)
|
||||
|
||||
## 贡献者 [![Good first issue](https://img.shields.io/github/labels/mermaid-js/mermaid/Good%20first%20issue%21)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%21%22) [![Contributors](https://img.shields.io/github/contributors/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) [![Commits](https://img.shields.io/github/commit-activity/m/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors)
|
||||
|
||||
Mermaid 是一个不断发展中的社区,并且还在接收新的贡献者。有很多不同的方式可以参与进来,而且我们还在寻找额外的帮助。如果你想知道如何开始贡献,请查看 [这个 issue](https://github.com/mermaid-js/mermaid/issues/866)。
|
||||
|
||||
关于如何贡献的详细信息可以在 [贡献指南](CONTRIBUTING.md) 中找到。
|
||||
|
||||
## 报告漏洞
|
||||
|
||||
如果想要报告漏洞,请发送邮件到 security@mermaid.live, 并附上问题的描述、复现问题的步骤、受影响的版本,以及解决问题的方案(如果有的话)。
|
||||
|
||||
## 鸣谢
|
||||
来自 Knut Sveidqvist:
|
||||
>*特别感谢 [d3](http://d3js.org/) 和 [dagre-d3](https://github.com/cpettitt/dagre-d3) 这两个优秀的项目,它们提供了图形布局和绘图工具库! *
|
||||
>*同样感谢 [js-sequence-diagram](http://bramp.github.io/js-sequence-diagrams) 提供了时序图语法的使用。 感谢 Jessica Peter 提供了甘特图渲染的灵感。*
|
||||
>*感谢 [Tyler Long](https://github.com/tylerlong) 从 2017年四月开始成为了项目的合作者。*
|
||||
>
|
||||
>*感谢越来越多的 [贡献者们](https://github.com/knsv/mermaid/graphs/contributors),没有你们,就没有这个项目的今天!*
|
||||
|
||||
---
|
||||
|
||||
*Mermaid 是由 Knut Sveidqvist 创建,它为了更简单的文档编写而生。*
|
@ -1,3 +1,3 @@
|
||||
export const curveBasis = 'basis'
|
||||
export const curveLinear = 'linear'
|
||||
export const curveCardinal = 'cardinal'
|
||||
export const curveBasis = 'basis';
|
||||
export const curveLinear = 'linear';
|
||||
export const curveCardinal = 'cardinal';
|
||||
|
71
__mocks__/d3.js
vendored
71
__mocks__/d3.js
vendored
@ -1,11 +1,10 @@
|
||||
/* eslint-env jest */
|
||||
let NewD3 = function () {
|
||||
function returnThis () {
|
||||
return this
|
||||
function returnThis() {
|
||||
return this;
|
||||
}
|
||||
return {
|
||||
append: function () {
|
||||
return NewD3()
|
||||
return NewD3();
|
||||
},
|
||||
lower: returnThis,
|
||||
attr: returnThis,
|
||||
@ -16,41 +15,47 @@ let NewD3 = function () {
|
||||
getBBox: function () {
|
||||
return {
|
||||
height: 10,
|
||||
width: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
width: 20,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const select = function () {
|
||||
return new NewD3()
|
||||
}
|
||||
return new NewD3();
|
||||
};
|
||||
|
||||
export const selectAll = function () {
|
||||
return new NewD3()
|
||||
}
|
||||
return new NewD3();
|
||||
};
|
||||
|
||||
export const curveBasis = 'basis'
|
||||
export const curveLinear = 'linear'
|
||||
export const curveCardinal = 'cardinal'
|
||||
export const curveBasis = 'basis';
|
||||
export const curveLinear = 'linear';
|
||||
export const curveCardinal = 'cardinal';
|
||||
|
||||
export const MockD3 = (name, parent) => {
|
||||
const children = []
|
||||
const children = [];
|
||||
const elem = {
|
||||
get __children () { return children },
|
||||
get __name () { return name },
|
||||
get __parent () { return parent }
|
||||
}
|
||||
get __children() {
|
||||
return children;
|
||||
},
|
||||
get __name() {
|
||||
return name;
|
||||
},
|
||||
get __parent() {
|
||||
return parent;
|
||||
},
|
||||
};
|
||||
elem.append = (name) => {
|
||||
const mockElem = MockD3(name, elem)
|
||||
children.push(mockElem)
|
||||
return mockElem
|
||||
}
|
||||
elem.lower = jest.fn(() => elem)
|
||||
elem.attr = jest.fn(() => elem)
|
||||
elem.text = jest.fn(() => elem)
|
||||
elem.style = jest.fn(() => elem)
|
||||
return elem
|
||||
}
|
||||
const mockElem = MockD3(name, elem);
|
||||
children.push(mockElem);
|
||||
return mockElem;
|
||||
};
|
||||
elem.lower = jest.fn(() => elem);
|
||||
elem.attr = jest.fn(() => elem);
|
||||
elem.text = jest.fn(() => elem);
|
||||
elem.style = jest.fn(() => elem);
|
||||
return elem;
|
||||
};
|
||||
|
@ -3,8 +3,8 @@ module.exports = {
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: "defaults, ie >= 11, current node"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
targets: 'defaults, ie >= 11, current node',
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
|
@ -1 +1,3 @@
|
||||
{ "video": false }
|
||||
{
|
||||
"video": false
|
||||
}
|
10
cypress/.eslintrc.json
Normal file
10
cypress/.eslintrc.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"env": {
|
||||
"cypress/globals": true
|
||||
},
|
||||
"extends": ["plugin:cypress/recommended"],
|
||||
"plugins": ["cypress"],
|
||||
"rules":{
|
||||
"cypress/no-unnecessary-waiting": 0
|
||||
}
|
||||
}
|
@ -2,15 +2,16 @@
|
||||
|
||||
context('Actions', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/actions')
|
||||
})
|
||||
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('fake@email.com')
|
||||
.should('have.value', 'fake@email.com')
|
||||
|
||||
// .type() with special character sequences
|
||||
.type('{leftarrow}{rightarrow}{uparrow}{downarrow}')
|
||||
@ -24,48 +25,52 @@ context('Actions', () => {
|
||||
|
||||
// Delay each keypress by 0.1 sec
|
||||
.type('slow.typing@email.com', { delay: 100 })
|
||||
.should('have.value', 'slow.typing@email.com')
|
||||
.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')
|
||||
})
|
||||
.should('have.value', 'disabled error checking');
|
||||
});
|
||||
|
||||
it('.focus() - focus on a DOM element', () => {
|
||||
// https://on.cypress.io/focus
|
||||
cy.get('.action-focus').focus()
|
||||
cy.get('.action-focus')
|
||||
.focus()
|
||||
.should('have.class', 'focus')
|
||||
.prev().should('have.attr', 'style', 'color: orange;')
|
||||
})
|
||||
.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()
|
||||
cy.get('.action-blur')
|
||||
.type('About to blur')
|
||||
.blur()
|
||||
.should('have.class', 'error')
|
||||
.prev().should('have.attr', 'style', 'color: red;')
|
||||
})
|
||||
.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')
|
||||
cy.get('.action-clear')
|
||||
.type('Clear this text')
|
||||
.should('have.value', 'Clear this text')
|
||||
.clear()
|
||||
.should('have.value', '')
|
||||
})
|
||||
.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!')
|
||||
})
|
||||
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()
|
||||
cy.get('.action-btn').click();
|
||||
|
||||
// You can click on 9 specific positions of an element:
|
||||
// -----------------------------------
|
||||
@ -81,16 +86,16 @@ context('Actions', () => {
|
||||
// -----------------------------------
|
||||
|
||||
// clicking in the center of the element is the default
|
||||
cy.get('#action-canvas').click()
|
||||
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')
|
||||
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 :)
|
||||
@ -102,90 +107,83 @@ context('Actions', () => {
|
||||
.click(100, 185)
|
||||
.click(125, 190)
|
||||
.click(150, 185)
|
||||
.click(170, 165)
|
||||
.click(170, 165);
|
||||
|
||||
// click multiple elements by passing multiple: true
|
||||
cy.get('.action-labels>.label').click({ multiple: true })
|
||||
cy.get('.action-labels>.label').click({ multiple: true });
|
||||
|
||||
// Ignore error checking prior to clicking
|
||||
cy.get('.action-opacity>.btn').click({ force: true })
|
||||
})
|
||||
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')
|
||||
})
|
||||
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-checkboxes [type="checkbox"]').not('[disabled]').check().should('be.checked');
|
||||
|
||||
cy.get('.action-radios [type="radio"]').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')
|
||||
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')
|
||||
.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-checkboxes [disabled]').check({ force: true }).should('be.checked');
|
||||
|
||||
cy.get('.action-radios [type="radio"]')
|
||||
.check('radio3', { 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')
|
||||
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('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')
|
||||
.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')
|
||||
})
|
||||
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').select('apples');
|
||||
|
||||
cy.get('.action-select-multiple')
|
||||
.select(['apples', 'oranges', 'bananas'])
|
||||
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').select('fr-bananas');
|
||||
|
||||
cy.get('.action-select-multiple')
|
||||
.select(['fr-apples', 'fr-oranges', '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
|
||||
@ -194,27 +192,21 @@ context('Actions', () => {
|
||||
// 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')
|
||||
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-horizontal button').scrollIntoView().should('be.visible');
|
||||
|
||||
cy.get('#scroll-vertical button')
|
||||
.should('not.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-vertical button').scrollIntoView().should('be.visible');
|
||||
|
||||
cy.get('#scroll-both button')
|
||||
.should('not.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')
|
||||
})
|
||||
cy.get('#scroll-both button').scrollIntoView().should('be.visible');
|
||||
});
|
||||
|
||||
it('.trigger() - trigger an event on a DOM element', () => {
|
||||
// https://on.cypress.io/trigger
|
||||
@ -228,12 +220,12 @@ context('Actions', () => {
|
||||
cy.get('.trigger-input-range')
|
||||
.invoke('val', 25)
|
||||
.trigger('change')
|
||||
.get('input[type=range]').siblings('p')
|
||||
.should('have.text', '25')
|
||||
})
|
||||
.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:
|
||||
@ -251,22 +243,22 @@ context('Actions', () => {
|
||||
|
||||
// if you chain .scrollTo() off of cy, we will
|
||||
// scroll the entire window
|
||||
cy.scrollTo('bottom')
|
||||
cy.scrollTo('bottom');
|
||||
|
||||
cy.get('#scrollable-horizontal').scrollTo('right')
|
||||
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)
|
||||
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%')
|
||||
cy.get('#scrollable-both').scrollTo('75%', '25%');
|
||||
|
||||
// control the easing of the scroll (default is 'swing')
|
||||
cy.get('#scrollable-vertical').scrollTo('center', { easing: 'linear' })
|
||||
cy.get('#scrollable-vertical').scrollTo('center', { easing: 'linear' });
|
||||
|
||||
// control the duration of the scroll (in ms)
|
||||
cy.get('#scrollable-both').scrollTo('center', { duration: 2000 })
|
||||
})
|
||||
})
|
||||
cy.get('#scrollable-both').scrollTo('center', { duration: 2000 });
|
||||
});
|
||||
});
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
context('Aliasing', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/aliasing')
|
||||
})
|
||||
cy.visit('https://example.cypress.io/commands/aliasing');
|
||||
});
|
||||
|
||||
it('.as() - alias a DOM element for later use', () => {
|
||||
// https://on.cypress.io/as
|
||||
@ -12,31 +12,25 @@ context('Aliasing', () => {
|
||||
// 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')
|
||||
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').click();
|
||||
|
||||
cy.get('@firstBtn')
|
||||
.should('have.class', 'btn-success')
|
||||
.and('contain', 'Changed')
|
||||
})
|
||||
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')
|
||||
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()
|
||||
cy.get('.network-btn').click();
|
||||
|
||||
// https://on.cypress.io/wait
|
||||
cy.wait('@getComment').its('status').should('eq', 200)
|
||||
|
||||
})
|
||||
})
|
||||
cy.wait('@getComment').its('status').should('eq', 200);
|
||||
});
|
||||
});
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
context('Assertions', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/assertions')
|
||||
})
|
||||
cy.visit('https://example.cypress.io/commands/assertions');
|
||||
});
|
||||
|
||||
describe('Implicit Assertions', () => {
|
||||
it('.should() - make an assertion about the current subject', () => {
|
||||
@ -23,7 +23,7 @@ context('Assertions', () => {
|
||||
// first need to invoke jQuery method text()
|
||||
// and then match using regular expression
|
||||
.invoke('text')
|
||||
.should('match', /column content/i)
|
||||
.should('match', /column content/i);
|
||||
|
||||
// a better way to check element's text content against a regular expression
|
||||
// is to use "cy.contains"
|
||||
@ -32,33 +32,33 @@ context('Assertions', () => {
|
||||
.find('tbody tr:last')
|
||||
// finds first <td> element with text content matching regular expression
|
||||
.contains('td', /column content/i)
|
||||
.should('be.visible')
|
||||
.should('be.visible');
|
||||
|
||||
// for more information about asserting element's text
|
||||
// see https://on.cypress.io/using-cypress-faq#How-do-I-get-an-element’s-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')
|
||||
})
|
||||
})
|
||||
.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(true).to.be.true;
|
||||
const o = { foo: 'bar' };
|
||||
|
||||
expect(o).to.equal(o)
|
||||
expect(o).to.deep.equal({ 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)
|
||||
})
|
||||
expect('FooBar').to.match(/bar$/i);
|
||||
});
|
||||
|
||||
it('pass your own callback function to should()', () => {
|
||||
// Pass a function to should that can have any number
|
||||
@ -71,14 +71,14 @@ context('Assertions', () => {
|
||||
// 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())
|
||||
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()
|
||||
const paragraphs = texts.get();
|
||||
|
||||
// array should have length of 3
|
||||
expect(paragraphs, 'has 3 paragraphs').to.have.length(3)
|
||||
expect(paragraphs, 'has 3 paragraphs').to.have.length(3);
|
||||
|
||||
// use second argument to expect(...) to provide clear
|
||||
// message with each assertion
|
||||
@ -86,27 +86,27 @@ context('Assertions', () => {
|
||||
'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)
|
||||
expect($div).to.have.length(1);
|
||||
|
||||
const className = $div[0].className
|
||||
const className = $div[0].className;
|
||||
|
||||
expect(className).to.match(/heading-/)
|
||||
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')
|
||||
})
|
||||
})
|
||||
expect($div, 'text content').to.have.text('Introduction');
|
||||
});
|
||||
});
|
||||
|
||||
it('can throw any error', () => {
|
||||
cy.get('.docs-header')
|
||||
@ -114,55 +114,56 @@ context('Assertions', () => {
|
||||
.should(($div) => {
|
||||
if ($div.length !== 1) {
|
||||
// you can throw your own errors
|
||||
throw new Error('Did not find 1 element')
|
||||
throw new Error('Did not find 1 element');
|
||||
}
|
||||
|
||||
const className = $div[0].className
|
||||
const className = $div[0].className;
|
||||
|
||||
if (!className.match(/heading-/)) {
|
||||
throw new Error(`Could not find class "heading-" in ${className}`)
|
||||
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
|
||||
*/
|
||||
let text;
|
||||
|
||||
/**
|
||||
* Normalizes passed text,
|
||||
* useful before comparing text with spaces and different capitalization.
|
||||
* 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()
|
||||
*/
|
||||
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())
|
||||
})
|
||||
text = normalizeText($first.text());
|
||||
});
|
||||
|
||||
cy.get('.two-elements')
|
||||
.find('.second')
|
||||
.should(($div) => {
|
||||
// we can massage text before comparing
|
||||
const secondText = normalizeText($div.text())
|
||||
const secondText = normalizeText($div.text());
|
||||
|
||||
expect(secondText, 'second text').to.equal(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')
|
||||
})
|
||||
})
|
||||
})
|
||||
assert.isObject(person, 'value is object');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -2,55 +2,54 @@
|
||||
|
||||
context('Connectors', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/connectors')
|
||||
})
|
||||
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)
|
||||
})
|
||||
})
|
||||
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)
|
||||
})
|
||||
.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')
|
||||
cy.get('.connectors-div')
|
||||
.should('be.hidden')
|
||||
// call the jquery method 'show' on the 'div.container'
|
||||
.invoke('show')
|
||||
.should('be.visible')
|
||||
})
|
||||
.should('be.visible');
|
||||
});
|
||||
|
||||
it('.spread() - spread an array as individual args to callback function', () => {
|
||||
// https://on.cypress.io/spread
|
||||
const arr = ['foo', 'bar', 'baz']
|
||||
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')
|
||||
})
|
||||
})
|
||||
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')
|
||||
})
|
||||
})
|
||||
})
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -2,77 +2,78 @@
|
||||
|
||||
context('Cookies', () => {
|
||||
beforeEach(() => {
|
||||
Cypress.Cookies.debug(true)
|
||||
Cypress.Cookies.debug(true);
|
||||
|
||||
cy.visit('https://example.cypress.io/commands/cookies')
|
||||
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()
|
||||
})
|
||||
cy.clearCookies();
|
||||
});
|
||||
|
||||
it('cy.getCookie() - get a browser cookie', () => {
|
||||
// https://on.cypress.io/getcookie
|
||||
cy.get('#getCookie .set-a-cookie').click()
|
||||
cy.get('#getCookie .set-a-cookie').click();
|
||||
|
||||
// cy.getCookie() yields a cookie object
|
||||
cy.getCookie('token').should('have.property', 'value', '123ABC')
|
||||
})
|
||||
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.getCookies().should('be.empty');
|
||||
|
||||
cy.get('#getCookies .set-a-cookie').click()
|
||||
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')
|
||||
})
|
||||
})
|
||||
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.getCookies().should('be.empty');
|
||||
|
||||
cy.setCookie('foo', 'bar')
|
||||
cy.setCookie('foo', 'bar');
|
||||
|
||||
// cy.getCookie() yields a cookie object
|
||||
cy.getCookie('foo').should('have.property', 'value', 'bar')
|
||||
})
|
||||
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.getCookie('token').should('be.null');
|
||||
|
||||
cy.get('#clearCookie .set-a-cookie').click()
|
||||
cy.get('#clearCookie .set-a-cookie').click();
|
||||
|
||||
cy.getCookie('token').should('have.property', 'value', '123ABC')
|
||||
cy.getCookie('token').should('have.property', 'value', '123ABC');
|
||||
|
||||
// cy.clearCookies() yields null
|
||||
cy.clearCookie('token').should('be.null')
|
||||
cy.clearCookie('token').should('be.null');
|
||||
|
||||
cy.getCookie('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.getCookies().should('be.empty');
|
||||
|
||||
cy.get('#clearCookies .set-a-cookie').click()
|
||||
cy.get('#clearCookies .set-a-cookie').click();
|
||||
|
||||
cy.getCookies().should('have.length', 1)
|
||||
cy.getCookies().should('have.length', 1);
|
||||
|
||||
// cy.clearCookies() yields null
|
||||
cy.clearCookies()
|
||||
cy.clearCookies();
|
||||
|
||||
cy.getCookies().should('be.empty')
|
||||
})
|
||||
})
|
||||
cy.getCookies().should('be.empty');
|
||||
});
|
||||
});
|
||||
|
@ -2,81 +2,85 @@
|
||||
|
||||
context('Cypress.Commands', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
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
|
||||
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'
|
||||
// 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)
|
||||
// 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
|
||||
})
|
||||
// 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
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
cy.get('button')
|
||||
.console('info')
|
||||
.then(($button) => {
|
||||
// subject is still $button
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('Cypress.Cookies', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
cy.visit('https://example.cypress.io/cypress-api');
|
||||
});
|
||||
|
||||
// https://on.cypress.io/cookies
|
||||
it('.debug() - enable or disable debugging', () => {
|
||||
Cypress.Cookies.debug(true)
|
||||
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')
|
||||
})
|
||||
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')
|
||||
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')
|
||||
})
|
||||
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')
|
||||
})
|
||||
cy.visit('https://example.cypress.io/cypress-api');
|
||||
});
|
||||
|
||||
// Permanently override server options for
|
||||
// all instances of cy.server()
|
||||
@ -86,71 +90,71 @@ context('Cypress.Server', () => {
|
||||
Cypress.Server.defaults({
|
||||
delay: 0,
|
||||
force404: false,
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('Cypress.arch', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
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
|
||||
})
|
||||
})
|
||||
expect(Cypress.arch).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
context('Cypress.config()', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
cy.visit('https://example.cypress.io/cypress-api');
|
||||
});
|
||||
|
||||
it('Get and set configuration options', () => {
|
||||
// https://on.cypress.io/config
|
||||
let myConfig = Cypress.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(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)
|
||||
expect(Cypress.config('pageLoadTimeout')).to.eq(60000);
|
||||
|
||||
// this will change the config for the rest of your tests!
|
||||
Cypress.config('pageLoadTimeout', 20000)
|
||||
Cypress.config('pageLoadTimeout', 20000);
|
||||
|
||||
expect(Cypress.config('pageLoadTimeout')).to.eq(20000)
|
||||
expect(Cypress.config('pageLoadTimeout')).to.eq(20000);
|
||||
|
||||
Cypress.config('pageLoadTimeout', 60000)
|
||||
})
|
||||
})
|
||||
Cypress.config('pageLoadTimeout', 60000);
|
||||
});
|
||||
});
|
||||
|
||||
context('Cypress.dom', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
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)
|
||||
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
|
||||
})
|
||||
})
|
||||
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')
|
||||
})
|
||||
cy.visit('https://example.cypress.io/cypress-api');
|
||||
});
|
||||
|
||||
// We can set environment variables for highly dynamic values
|
||||
|
||||
@ -161,62 +165,61 @@ context('Cypress.env()', () => {
|
||||
Cypress.env({
|
||||
host: 'veronica.dev.local',
|
||||
api_server: 'http://localhost:8888/v1/',
|
||||
})
|
||||
});
|
||||
|
||||
// get environment variable
|
||||
expect(Cypress.env('host')).to.eq('veronica.dev.local')
|
||||
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/')
|
||||
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/')
|
||||
})
|
||||
})
|
||||
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')
|
||||
})
|
||||
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')
|
||||
})
|
||||
cy.visit('https://example.cypress.io/cypress-api');
|
||||
});
|
||||
|
||||
it('Get underlying OS name', () => {
|
||||
// https://on.cypress.io/platform
|
||||
expect(Cypress.platform).to.be.exist
|
||||
})
|
||||
})
|
||||
expect(Cypress.platform).to.be.exist;
|
||||
});
|
||||
});
|
||||
|
||||
context('Cypress.version', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
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
|
||||
})
|
||||
})
|
||||
expect(Cypress.version).to.be.exist;
|
||||
});
|
||||
});
|
||||
|
||||
context('Cypress.spec', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
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'])
|
||||
})
|
||||
})
|
||||
cy.wrap(Cypress.spec).should('have.keys', ['name', 'relative', 'absolute']);
|
||||
});
|
||||
});
|
||||
|
@ -3,18 +3,18 @@
|
||||
/// JSON fixture file can be loaded directly using
|
||||
// the built-in JavaScript bundler
|
||||
// @ts-ignore
|
||||
const requiredExample = require('../../fixtures/example')
|
||||
const requiredExample = require('../../fixtures/example');
|
||||
|
||||
context('Files', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/files')
|
||||
})
|
||||
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')
|
||||
})
|
||||
cy.fixture('example.json').as('example');
|
||||
});
|
||||
|
||||
it('cy.fixture() - load a fixture', () => {
|
||||
// https://on.cypress.io/fixture
|
||||
@ -22,57 +22,58 @@ context('Files', () => {
|
||||
// Instead of writing a response inline you can
|
||||
// use a fixture file's content.
|
||||
|
||||
cy.server()
|
||||
cy.fixture('example.json').as('comment')
|
||||
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')
|
||||
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.get('.fixture-btn').click();
|
||||
|
||||
cy.wait('@getComment').its('responseBody')
|
||||
cy.wait('@getComment')
|
||||
.its('responseBody')
|
||||
.should('have.property', 'name')
|
||||
.and('include', 'Using fixtures to represent data')
|
||||
.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')
|
||||
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.get('.fixture-btn').click();
|
||||
|
||||
cy.wait('@getComment').its('responseBody')
|
||||
cy.wait('@getComment')
|
||||
.its('responseBody')
|
||||
.should('have.property', 'name')
|
||||
.and('include', 'Using fixtures to represent data')
|
||||
.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')
|
||||
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.get('.fixture-btn').click();
|
||||
|
||||
cy.wait('@getComment').its('responseBody')
|
||||
cy.wait('@getComment')
|
||||
.its('responseBody')
|
||||
.should('have.property', 'name')
|
||||
.and('include', 'Using fixtures to represent data')
|
||||
})
|
||||
.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)
|
||||
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)
|
||||
})
|
||||
cy.wrap(this.example, 'fixture vs require').should('deep.equal', requiredExample);
|
||||
});
|
||||
|
||||
it('cy.readFile() - read a files contents', () => {
|
||||
// https://on.cypress.io/readfile
|
||||
@ -80,9 +81,9 @@ context('Files', () => {
|
||||
// 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')
|
||||
})
|
||||
})
|
||||
expect(json).to.be.an('object');
|
||||
});
|
||||
});
|
||||
|
||||
it('cy.writeFile() - write to a file', () => {
|
||||
// https://on.cypress.io/writefile
|
||||
@ -91,13 +92,12 @@ context('Files', () => {
|
||||
|
||||
// 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.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
|
||||
})
|
||||
expect(users[0].name).to.exist;
|
||||
});
|
||||
|
||||
// JavaScript arrays and objects are stringified
|
||||
// and formatted into text.
|
||||
@ -105,10 +105,10 @@ context('Files', () => {
|
||||
id: 8739,
|
||||
name: 'Jane',
|
||||
email: 'jane@example.com',
|
||||
})
|
||||
});
|
||||
|
||||
cy.fixture('profile').should((profile) => {
|
||||
expect(profile.name).to.eq('Jane')
|
||||
})
|
||||
})
|
||||
})
|
||||
expect(profile.name).to.eq('Jane');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -2,51 +2,57 @@
|
||||
|
||||
context('Local Storage', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/local-storage')
|
||||
})
|
||||
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')
|
||||
})
|
||||
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
|
||||
})
|
||||
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.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')
|
||||
})
|
||||
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.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')
|
||||
})
|
||||
})
|
||||
})
|
||||
expect(ls.getItem('prop1')).to.be.null;
|
||||
expect(ls.getItem('prop2')).to.be.null;
|
||||
expect(ls.getItem('prop3')).to.eq('magenta');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -2,31 +2,31 @@
|
||||
|
||||
context('Location', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/location')
|
||||
})
|
||||
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')
|
||||
})
|
||||
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
|
||||
})
|
||||
})
|
||||
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')
|
||||
})
|
||||
})
|
||||
cy.url().should('eq', 'https://example.cypress.io/commands/location');
|
||||
});
|
||||
});
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
context('Misc', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/misc')
|
||||
})
|
||||
cy.visit('https://example.cypress.io/commands/misc');
|
||||
});
|
||||
|
||||
it('.end() - end the command chain', () => {
|
||||
// https://on.cypress.io/end
|
||||
@ -12,12 +12,12 @@ context('Misc', () => {
|
||||
// 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()
|
||||
cy.contains('Cheryl').click().end();
|
||||
|
||||
// queries the entire table again
|
||||
cy.contains('Charles').click()
|
||||
})
|
||||
})
|
||||
cy.contains('Charles').click();
|
||||
});
|
||||
});
|
||||
|
||||
it('cy.exec() - execute a system command', () => {
|
||||
// https://on.cypress.io/exec
|
||||
@ -25,40 +25,36 @@ context('Misc', () => {
|
||||
// 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')
|
||||
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}`)
|
||||
cy.log(`Platform ${Cypress.platform} architecture ${Cypress.arch}`);
|
||||
|
||||
if (Cypress.platform === 'win32') {
|
||||
cy.exec('print cypress.json')
|
||||
.its('stderr').should('be.empty')
|
||||
cy.exec('print cypress.json').its('stderr').should('be.empty');
|
||||
} else {
|
||||
cy.exec('cat cypress.json')
|
||||
.its('stderr').should('be.empty')
|
||||
cy.exec('cat cypress.json').its('stderr').should('be.empty');
|
||||
|
||||
cy.exec('pwd')
|
||||
.its('code').should('eq', 0)
|
||||
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('#name').click();
|
||||
cy.focused().should('have.id', 'name');
|
||||
|
||||
cy.get('.misc-form').find('#description').click()
|
||||
cy.focused().should('have.id', 'description')
|
||||
})
|
||||
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')
|
||||
})
|
||||
cy.screenshot('my-image');
|
||||
});
|
||||
|
||||
it('Cypress.Screenshot.defaults() - change default config of screenshots', function () {
|
||||
Cypress.Screenshot.defaults({
|
||||
@ -68,16 +64,14 @@ context('Misc', () => {
|
||||
scale: false,
|
||||
disableTimersAndAnimations: true,
|
||||
screenshotOnRunFailure: true,
|
||||
beforeScreenshot () { },
|
||||
afterScreenshot () { },
|
||||
})
|
||||
})
|
||||
})
|
||||
beforeScreenshot() {},
|
||||
afterScreenshot() {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('cy.wrap() - wrap an object', () => {
|
||||
// https://on.cypress.io/wrap
|
||||
cy.wrap({ foo: 'bar' })
|
||||
.should('have.property', 'foo')
|
||||
.and('include', 'bar')
|
||||
})
|
||||
})
|
||||
cy.wrap({ foo: 'bar' }).should('have.property', 'foo').and('include', 'bar');
|
||||
});
|
||||
});
|
||||
|
@ -2,38 +2,38 @@
|
||||
|
||||
context('Navigation', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io')
|
||||
cy.get('.navbar-nav').contains('Commands').click()
|
||||
cy.get('.dropdown-menu').contains('Navigation').click()
|
||||
})
|
||||
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', () => {
|
||||
it("cy.go() - go back or forward in the browser's history", () => {
|
||||
// https://on.cypress.io/go
|
||||
|
||||
cy.location('pathname').should('include', 'navigation')
|
||||
cy.location('pathname').should('include', 'navigation');
|
||||
|
||||
cy.go('back')
|
||||
cy.location('pathname').should('not.include', 'navigation')
|
||||
cy.go('back');
|
||||
cy.location('pathname').should('not.include', 'navigation');
|
||||
|
||||
cy.go('forward')
|
||||
cy.location('pathname').should('include', 'navigation')
|
||||
cy.go('forward');
|
||||
cy.location('pathname').should('include', 'navigation');
|
||||
|
||||
// clicking back
|
||||
cy.go(-1)
|
||||
cy.location('pathname').should('not.include', 'navigation')
|
||||
cy.go(-1);
|
||||
cy.location('pathname').should('not.include', 'navigation');
|
||||
|
||||
// clicking forward
|
||||
cy.go(1)
|
||||
cy.location('pathname').should('include', 'navigation')
|
||||
})
|
||||
cy.go(1);
|
||||
cy.location('pathname').should('include', 'navigation');
|
||||
});
|
||||
|
||||
it('cy.reload() - reload the page', () => {
|
||||
// https://on.cypress.io/reload
|
||||
cy.reload()
|
||||
cy.reload();
|
||||
|
||||
// reload the page without using the cache
|
||||
cy.reload(true)
|
||||
})
|
||||
cy.reload(true);
|
||||
});
|
||||
|
||||
it('cy.visit() - visit a remote url', () => {
|
||||
// https://on.cypress.io/visit
|
||||
@ -43,14 +43,14 @@ context('Navigation', () => {
|
||||
// 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) {
|
||||
onBeforeLoad(contentWindow) {
|
||||
// contentWindow is the remote page's window object
|
||||
expect(typeof contentWindow === 'object').to.be.true
|
||||
expect(typeof contentWindow === 'object').to.be.true;
|
||||
},
|
||||
onLoad (contentWindow) {
|
||||
onLoad(contentWindow) {
|
||||
// contentWindow is the remote page's window object
|
||||
expect(typeof contentWindow === 'object').to.be.true
|
||||
expect(typeof contentWindow === 'object').to.be.true;
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
context('Network Requests', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/network-requests')
|
||||
})
|
||||
cy.visit('https://example.cypress.io/commands/network-requests');
|
||||
});
|
||||
|
||||
// Manage AJAX / XHR requests in your app
|
||||
|
||||
@ -13,59 +13,56 @@ context('Network Requests', () => {
|
||||
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
|
||||
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
|
||||
expect(server.enable).to.be.true;
|
||||
// forces requests that don't match your routes to 404
|
||||
expect(server.force404).to.be.false
|
||||
expect(server.force404).to.be.false;
|
||||
// whitelists requests from ever being logged or stubbed
|
||||
expect(server.whitelist).to.be.a('function')
|
||||
})
|
||||
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')
|
||||
})
|
||||
})
|
||||
|
||||
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) => {
|
||||
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')
|
||||
})
|
||||
})
|
||||
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
|
||||
@ -77,42 +74,42 @@ context('Network Requests', () => {
|
||||
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,
|
||||
})
|
||||
})
|
||||
.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')
|
||||
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('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')
|
||||
})
|
||||
})
|
||||
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
|
||||
@ -131,47 +128,48 @@ context('Network Requests', () => {
|
||||
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
|
||||
.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)
|
||||
})
|
||||
})
|
||||
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'
|
||||
let message = 'whoa, this comment does not exist';
|
||||
|
||||
cy.server()
|
||||
cy.server();
|
||||
|
||||
// Listen to GET to comments/1
|
||||
cy.route('GET', 'comments/*').as('getComment')
|
||||
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()
|
||||
cy.get('.network-btn').click();
|
||||
|
||||
// https://on.cypress.io/wait
|
||||
cy.wait('@getComment').its('status').should('eq', 200)
|
||||
cy.wait('@getComment').its('status').should('eq', 200);
|
||||
|
||||
// Listen to POST to comments
|
||||
cy.route('POST', '/comments').as('postComment')
|
||||
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')
|
||||
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()')
|
||||
})
|
||||
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({
|
||||
@ -180,15 +178,15 @@ context('Network Requests', () => {
|
||||
status: 404,
|
||||
response: { error: message },
|
||||
delay: 500,
|
||||
}).as('putComment')
|
||||
}).as('putComment');
|
||||
|
||||
// we have code that puts a comment when
|
||||
// the button is clicked in scripts.js
|
||||
cy.get('.network-put').click()
|
||||
cy.get('.network-put').click();
|
||||
|
||||
cy.wait('@putComment')
|
||||
cy.wait('@putComment');
|
||||
|
||||
// our 404 statusCode logic in scripts.js executed
|
||||
cy.get('.network-put-comment').should('contain', message)
|
||||
})
|
||||
})
|
||||
cy.get('.network-put-comment').should('contain', message);
|
||||
});
|
||||
});
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
context('Querying', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/querying')
|
||||
})
|
||||
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
|
||||
@ -11,77 +11,65 @@ context('Querying', () => {
|
||||
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('.query-btn').should('contain', 'Button')
|
||||
cy.get('.query-btn').should('contain', 'Button');
|
||||
|
||||
cy.get('#querying .well>button:first').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('[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')
|
||||
.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')
|
||||
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')
|
||||
})
|
||||
.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')
|
||||
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(/^b\w+/).should('have.class', 'third');
|
||||
|
||||
cy.get('.query-list')
|
||||
.contains('apples')
|
||||
.should('have.class', 'first')
|
||||
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('#querying').contains('ul', 'oranges').should('have.class', 'query-list');
|
||||
|
||||
cy.get('.query-button')
|
||||
.contains('Save Form')
|
||||
.should('have.class', 'btn')
|
||||
})
|
||||
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')
|
||||
})
|
||||
})
|
||||
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.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')
|
||||
})
|
||||
})
|
||||
})
|
||||
cy.root().should('have.class', 'query-ul');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -3,93 +3,92 @@
|
||||
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')
|
||||
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks');
|
||||
|
||||
const obj = {
|
||||
foo () {},
|
||||
}
|
||||
foo() {},
|
||||
};
|
||||
|
||||
const spy = cy.spy(obj, 'foo').as('anyArgs')
|
||||
const spy = cy.spy(obj, 'foo').as('anyArgs');
|
||||
|
||||
obj.foo()
|
||||
obj.foo();
|
||||
|
||||
expect(spy).to.be.called
|
||||
})
|
||||
expect(spy).to.be.called;
|
||||
});
|
||||
|
||||
it('cy.spy() retries until assertions pass', () => {
|
||||
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks')
|
||||
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)
|
||||
*/
|
||||
foo(x) {
|
||||
console.log('obj.foo called with', x);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
cy.spy(obj, 'foo').as('foo')
|
||||
cy.spy(obj, 'foo').as('foo');
|
||||
|
||||
setTimeout(() => {
|
||||
obj.foo('first')
|
||||
}, 500)
|
||||
obj.foo('first');
|
||||
}, 500);
|
||||
|
||||
setTimeout(() => {
|
||||
obj.foo('second')
|
||||
}, 2500)
|
||||
obj.foo('second');
|
||||
}, 2500);
|
||||
|
||||
cy.get('@foo').should('have.been.calledTwice')
|
||||
})
|
||||
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')
|
||||
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks');
|
||||
|
||||
const obj = {
|
||||
/**
|
||||
* prints both arguments to the console
|
||||
* Prints both arguments to the console
|
||||
*
|
||||
* @param a {string}
|
||||
* @param b {string}
|
||||
*/
|
||||
foo (a, b) {
|
||||
console.log('a', a, 'b', b)
|
||||
*/
|
||||
foo(a, b) {
|
||||
console.log('a', a, 'b', b);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
const stub = cy.stub(obj, 'foo').as('foo')
|
||||
const stub = cy.stub(obj, 'foo').as('foo');
|
||||
|
||||
obj.foo('foo', 'bar')
|
||||
obj.foo('foo', 'bar');
|
||||
|
||||
expect(stub).to.be.called
|
||||
})
|
||||
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()
|
||||
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')
|
||||
})
|
||||
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()
|
||||
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')
|
||||
})
|
||||
})
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
@ -2,120 +2,96 @@
|
||||
|
||||
context('Traversal', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/traversal')
|
||||
})
|
||||
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')
|
||||
})
|
||||
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')
|
||||
})
|
||||
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')
|
||||
})
|
||||
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')
|
||||
})
|
||||
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)
|
||||
})
|
||||
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')
|
||||
})
|
||||
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')
|
||||
})
|
||||
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')
|
||||
})
|
||||
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)
|
||||
})
|
||||
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)
|
||||
})
|
||||
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')
|
||||
})
|
||||
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')
|
||||
})
|
||||
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')
|
||||
})
|
||||
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)
|
||||
})
|
||||
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')
|
||||
})
|
||||
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)
|
||||
})
|
||||
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)
|
||||
})
|
||||
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)
|
||||
})
|
||||
})
|
||||
cy.get('.traversal-pills .active').siblings().should('have.length', 2);
|
||||
});
|
||||
});
|
||||
|
@ -2,132 +2,128 @@
|
||||
|
||||
context('Utilities', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/utilities')
|
||||
})
|
||||
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()
|
||||
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])
|
||||
})
|
||||
})
|
||||
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')
|
||||
let $li = Cypress.$('.utility-jquery li:first');
|
||||
|
||||
cy.wrap($li)
|
||||
.should('not.have.class', 'active')
|
||||
.click()
|
||||
.should('have.class', 'active')
|
||||
})
|
||||
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) => {
|
||||
// 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 })
|
||||
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)
|
||||
$div.append(img);
|
||||
|
||||
cy.get('.utility-blob img').click()
|
||||
.should('have.attr', 'src', dataUrl)
|
||||
}))
|
||||
})
|
||||
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
|
||||
expect(matching, 'matching wildcard').to.be.true;
|
||||
|
||||
matching = Cypress.minimatch('/users/1/comments/2', '/users/*/comments', {
|
||||
matchBase: true,
|
||||
})
|
||||
expect(matching, 'comments').to.be.false
|
||||
});
|
||||
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
|
||||
});
|
||||
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
|
||||
})
|
||||
|
||||
});
|
||||
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')
|
||||
const time = Cypress.moment().utc('2014-04-25T19:38:53.196Z').format('h:mm A');
|
||||
|
||||
expect(time).to.be.a('string')
|
||||
expect(time).to.be.a('string');
|
||||
|
||||
cy.get('.utility-moment').contains('3:38 PM')
|
||||
.should('have.class', 'badge')
|
||||
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')
|
||||
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')
|
||||
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
|
||||
})
|
||||
})
|
||||
// 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
|
||||
let waited = false;
|
||||
|
||||
/**
|
||||
* @return Bluebird<string>
|
||||
*/
|
||||
function waitOneSecond () {
|
||||
/** @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
|
||||
waited = true;
|
||||
|
||||
// resolve with 'foo' string
|
||||
resolve('foo')
|
||||
}, 1000)
|
||||
})
|
||||
resolve('foo');
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
cy.then(() =>
|
||||
// return a promise to cy.then() that
|
||||
// is awaited until it resolves
|
||||
// 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
|
||||
}))
|
||||
})
|
||||
})
|
||||
expect(str).to.eq('foo');
|
||||
expect(waited).to.be.true;
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -2,22 +2,22 @@
|
||||
|
||||
context('Viewport', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/viewport')
|
||||
})
|
||||
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)
|
||||
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')
|
||||
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(2999, 2999);
|
||||
|
||||
// cy.viewport() accepts a set of preset sizes
|
||||
// to easily set the screen to a device's width and height
|
||||
@ -25,35 +25,35 @@ context('Viewport', () => {
|
||||
// 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('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)
|
||||
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)
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
@ -2,33 +2,32 @@
|
||||
|
||||
context('Waiting', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/waiting')
|
||||
})
|
||||
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)
|
||||
})
|
||||
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()
|
||||
cy.server();
|
||||
|
||||
// Listen to GET to comments/1
|
||||
cy.route('GET', 'comments/*').as('getComment')
|
||||
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()
|
||||
cy.get('.network-btn').click();
|
||||
|
||||
// wait for GET comments/1
|
||||
cy.wait('@getComment').its('status').should('eq', 200)
|
||||
})
|
||||
|
||||
})
|
||||
cy.wait('@getComment').its('status').should('eq', 200);
|
||||
});
|
||||
});
|
||||
|
@ -2,21 +2,21 @@
|
||||
|
||||
context('Window', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/window')
|
||||
})
|
||||
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')
|
||||
})
|
||||
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')
|
||||
})
|
||||
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')
|
||||
})
|
||||
})
|
||||
cy.title().should('include', 'Kitchen Sink');
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
@ -1,11 +1,9 @@
|
||||
/* eslint-env jest */
|
||||
/* global cy */
|
||||
import { Base64 } from 'js-base64';
|
||||
|
||||
export const mermaidUrl = (graphStr, options, api) => {
|
||||
const obj = {
|
||||
code: graphStr,
|
||||
mermaid: options
|
||||
mermaid: options,
|
||||
};
|
||||
const objStr = JSON.stringify(obj);
|
||||
let url = 'http://localhost:9000/e2e.html?graph=' + Base64.encodeURI(objStr);
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { renderGraph } from '../../helpers/util';
|
||||
/* eslint-env jest */
|
||||
describe('Configuration', () => {
|
||||
describe('arrowMarkerAbsolute', () => {
|
||||
it('should handle default value false of arrowMarkerAbsolute', () => {
|
||||
@ -11,12 +10,14 @@ describe('Configuration', () => {
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ }
|
||||
{}
|
||||
);
|
||||
|
||||
// Check the marker-end property to make sure it is properly set to
|
||||
// start with #
|
||||
cy.get('.edgePath path').first().should('have.attr', 'marker-end')
|
||||
cy.get('.edgePath path')
|
||||
.first()
|
||||
.should('have.attr', 'marker-end')
|
||||
.should('exist')
|
||||
.and('include', 'url(#');
|
||||
});
|
||||
@ -29,12 +30,14 @@ describe('Configuration', () => {
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ }
|
||||
{}
|
||||
);
|
||||
|
||||
// Check the marker-end property to make sure it is properly set to
|
||||
// start with #
|
||||
cy.get('.edgePath path').first().should('have.attr', 'marker-end')
|
||||
cy.get('.edgePath path')
|
||||
.first()
|
||||
.should('have.attr', 'marker-end')
|
||||
.should('exist')
|
||||
.and('include', 'url(#');
|
||||
});
|
||||
@ -48,13 +51,15 @@ describe('Configuration', () => {
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{
|
||||
arrowMarkerAbsolute: false
|
||||
arrowMarkerAbsolute: false,
|
||||
}
|
||||
);
|
||||
|
||||
// Check the marker-end property to make sure it is properly set to
|
||||
// start with #
|
||||
cy.get('.edgePath path').first().should('have.attr', 'marker-end')
|
||||
cy.get('.edgePath path')
|
||||
.first()
|
||||
.should('have.attr', 'marker-end')
|
||||
.should('exist')
|
||||
.and('include', 'url(#');
|
||||
});
|
||||
@ -68,13 +73,15 @@ describe('Configuration', () => {
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{
|
||||
arrowMarkerAbsolute: "false"
|
||||
arrowMarkerAbsolute: 'false',
|
||||
}
|
||||
);
|
||||
|
||||
// Check the marker-end property to make sure it is properly set to
|
||||
// start with #
|
||||
cy.get('.edgePath path').first().should('have.attr', 'marker-end')
|
||||
cy.get('.edgePath path')
|
||||
.first()
|
||||
.should('have.attr', 'marker-end')
|
||||
.should('exist')
|
||||
.and('include', 'url(#');
|
||||
});
|
||||
@ -88,13 +95,23 @@ describe('Configuration', () => {
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{
|
||||
arrowMarkerAbsolute: true
|
||||
arrowMarkerAbsolute: true,
|
||||
}
|
||||
);
|
||||
|
||||
cy.get('.edgePath path').first().should('have.attr', 'marker-end')
|
||||
cy.get('.edgePath path')
|
||||
.first()
|
||||
.should('have.attr', 'marker-end')
|
||||
.should('exist')
|
||||
.and('include', 'url(http://localhost');
|
||||
});
|
||||
it('should not taint the initial configuration when using multiple directives', () => {
|
||||
const url = 'http://localhost:9000/regression/issue-1874.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
|
||||
cy.get('svg');
|
||||
cy.percySnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,35 +1,36 @@
|
||||
/* eslint-env jest */
|
||||
describe('Interaction', () => {
|
||||
describe('Interaction - security level loose', () => {
|
||||
it('Graph: should handle a click on a node with a bound function', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g#flowchart-Function-2')
|
||||
.click();
|
||||
cy.get('body').find('g#flowchart-Function-2').click();
|
||||
|
||||
cy.get('.created-by-click').should('have.text', 'Clicked By Flow');
|
||||
});
|
||||
it('Graph: should handle a click on a node with a bound function where the node starts with a number', () => {
|
||||
it('Graph: should handle a click on a node with a bound function with args', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g[id="flowchart-1Function-6"]')
|
||||
.click();
|
||||
cy.get('body').find('g#flowchart-FunctionArg-18').click();
|
||||
|
||||
cy.get('.created-by-click').should('have.text', 'Clicked By Flow');
|
||||
cy.get('.created-by-click-2').should('have.text', 'Clicked By Flow: ARGUMENT');
|
||||
});
|
||||
it('Flowchart: should handle a click on a node with a bound function where the node starts with a number', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body').find('g[id="flowchart-FunctionArg-22"]').click();
|
||||
|
||||
cy.get('.created-by-click-2').should('have.text', 'Clicked By Flow: ARGUMENT');
|
||||
});
|
||||
it('Graph: should handle a click on a node with a bound url', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('#flowchart-URL-3')
|
||||
.click();
|
||||
cy.get('body').find('#flowchart-URL-3').click();
|
||||
|
||||
cy.location().should(location => {
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
});
|
||||
});
|
||||
@ -37,11 +38,9 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g[id="flowchart-2URL-7"]')
|
||||
.click();
|
||||
cy.get('body').find('g[id="flowchart-2URL-7"]').click();
|
||||
|
||||
cy.location().should(location => {
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
});
|
||||
});
|
||||
@ -50,9 +49,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g#flowchart-Function-10')
|
||||
.click();
|
||||
cy.get('body').find('g#flowchart-Function-10').click();
|
||||
|
||||
cy.get('.created-by-click').should('have.text', 'Clicked By Flow');
|
||||
});
|
||||
@ -60,9 +57,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g[id="flowchart-1Function-14"]')
|
||||
.click();
|
||||
cy.get('body').find('g[id="flowchart-1Function-14"]').click();
|
||||
|
||||
cy.get('.created-by-click').should('have.text', 'Clicked By Flow');
|
||||
});
|
||||
@ -70,11 +65,9 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('#flowchart-URL-11')
|
||||
.click();
|
||||
cy.get('body').find('#flowchart-URL-11').click();
|
||||
|
||||
cy.location().should(location => {
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
});
|
||||
});
|
||||
@ -82,11 +75,9 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g[id="flowchart-2URL-15"]')
|
||||
.click();
|
||||
cy.get('body').find('g[id="flowchart-2URL-15"]').click();
|
||||
|
||||
cy.location().should(location => {
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
});
|
||||
});
|
||||
@ -95,11 +86,9 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('rect#cl1')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('rect#cl1').click({ force: true });
|
||||
|
||||
cy.location().should(location => {
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
});
|
||||
});
|
||||
@ -107,11 +96,9 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('text#cl1-text')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('text#cl1-text').click({ force: true });
|
||||
|
||||
cy.location().should(location => {
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
});
|
||||
});
|
||||
@ -119,9 +106,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('rect#cl2')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('rect#cl2').click({ force: true });
|
||||
|
||||
cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant cl2');
|
||||
});
|
||||
@ -129,9 +114,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('rect#cl3')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('rect#cl3').click({ force: true });
|
||||
|
||||
cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant test1 test2 test3');
|
||||
});
|
||||
@ -140,9 +123,7 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('text#cl2-text')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('text#cl2-text').click({ force: true });
|
||||
|
||||
cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant cl2');
|
||||
});
|
||||
@ -150,13 +131,10 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_loose.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('text#cl3-text')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('text#cl3-text').click({ force: true });
|
||||
|
||||
cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant test1 test2 test3');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Interaction - security level tight', () => {
|
||||
@ -164,31 +142,27 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_strict.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g#flowchart-Function-2')
|
||||
.click();
|
||||
cy.get('body').find('g#flowchart-Function-2').click();
|
||||
|
||||
cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
|
||||
cy.get('.created-by-click').should('not.exist');
|
||||
// cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
|
||||
});
|
||||
it('should handle a click on a node with a bound function where the node starts with a number', () => {
|
||||
const url = 'http://localhost:9000/click_security_strict.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g[id="flowchart-1Function-6"]')
|
||||
.click();
|
||||
cy.get('body').find('g[id="flowchart-1Function-6"]').click();
|
||||
|
||||
cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
|
||||
// cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
|
||||
cy.get('.created-by-click').should('not.exist');
|
||||
});
|
||||
it('should handle a click on a node with a bound url', () => {
|
||||
const url = 'http://localhost:9000/click_security_strict.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g#flowchart-URL-3')
|
||||
.click();
|
||||
cy.get('body').find('g#flowchart-URL-3').click();
|
||||
|
||||
cy.location().should(location => {
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
});
|
||||
});
|
||||
@ -196,11 +170,9 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_strict.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g[id="flowchart-2URL-7"]')
|
||||
.click();
|
||||
cy.get('body').find('g[id="flowchart-2URL-7"]').click();
|
||||
|
||||
cy.location().should(location => {
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
});
|
||||
});
|
||||
@ -209,11 +181,9 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_strict.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('rect#cl1')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('rect#cl1').click({ force: true });
|
||||
|
||||
cy.location().should(location => {
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
});
|
||||
});
|
||||
@ -221,11 +191,9 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_strict.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('text#cl1-text')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('text#cl1-text').click({ force: true });
|
||||
|
||||
cy.location().should(location => {
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
});
|
||||
});
|
||||
@ -233,21 +201,19 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_strict.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('rect#cl2')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('rect#cl2').click({ force: true });
|
||||
|
||||
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
|
||||
// cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
|
||||
cy.get('.created-by-gant-click').should('not.exist');
|
||||
});
|
||||
it('should handle a click on a task with a bound function', () => {
|
||||
const url = 'http://localhost:9000/click_security_strict.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('text#cl2-text')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('text#cl2-text').click({ force: true });
|
||||
|
||||
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
|
||||
// cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
|
||||
cy.get('.created-by-gant-click').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
@ -256,31 +222,27 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_other.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g#flowchart-Function-2')
|
||||
.click();
|
||||
cy.get('body').find('g#flowchart-Function-2').click();
|
||||
|
||||
cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
|
||||
// cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
|
||||
cy.get('.created-by-click').should('not.exist');
|
||||
});
|
||||
it('should handle a click on a node with a bound function where the node starts with a number', () => {
|
||||
const url = 'http://localhost:9000/click_security_other.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g[id="flowchart-1Function-6"]')
|
||||
.click();
|
||||
cy.get('body').find('g[id="flowchart-1Function-6"]').click();
|
||||
|
||||
cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow');
|
||||
cy.get('.created-by-click').should('not.exist');
|
||||
cy.get('.created-by-click').should('not.exist');
|
||||
});
|
||||
it('should handle a click on a node with a bound url', () => {
|
||||
const url = 'http://localhost:9000/click_security_other.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('g#flowchart-URL-3')
|
||||
.click();
|
||||
cy.get('body').find('g#flowchart-URL-3').click();
|
||||
|
||||
cy.location().should(location => {
|
||||
cy.location().should((location) => {
|
||||
expect(location.href).to.eq('http://localhost:9000/webpackUsage.html');
|
||||
});
|
||||
});
|
||||
@ -289,21 +251,17 @@ describe('Interaction', () => {
|
||||
const url = 'http://localhost:9000/click_security_other.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('rect#cl2')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('rect#cl2').click({ force: true });
|
||||
|
||||
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
|
||||
cy.get('.created-by-gant-click').should('not.exist');
|
||||
});
|
||||
it('should handle a click on a task with a bound function', () => {
|
||||
const url = 'http://localhost:9000/click_security_other.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('text#cl2-text')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('text#cl2-text').click({ force: true });
|
||||
|
||||
cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2');
|
||||
cy.get('.created-by-gant-click').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,22 +1,19 @@
|
||||
/* eslint-env jest */
|
||||
describe('Rerendering', () => {
|
||||
it('should be able to render after an error has occured', () => {
|
||||
const url = 'http://localhost:9000/render-after-error.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('#graphDiv').should('exist');
|
||||
});
|
||||
it('should be able to render after an error has occured', () => {
|
||||
const url = 'http://localhost:9000/render-after-error.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('#graphDiv').should('exist');
|
||||
});
|
||||
|
||||
it('should be able to render and rerender a graph via API', () => {
|
||||
const url = 'http://localhost:9000/rerender.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('#graph [id^=flowchart-A]').should('have.text', 'XMas');
|
||||
it('should be able to render and rerender a graph via API', () => {
|
||||
const url = 'http://localhost:9000/rerender.html';
|
||||
cy.viewport(1440, 1024);
|
||||
cy.visit(url);
|
||||
cy.get('#graph [id^=flowchart-A]').should('have.text', 'XMas');
|
||||
|
||||
cy.get('body')
|
||||
.find('#rerender')
|
||||
.click({ force: true });
|
||||
cy.get('body').find('#rerender').click({ force: true });
|
||||
|
||||
cy.get('#graph [id^=flowchart-A]').should('have.text', 'Saturday');
|
||||
});
|
||||
cy.get('#graph [id^=flowchart-A]').should('have.text', 'Saturday');
|
||||
});
|
||||
});
|
||||
|
@ -1,21 +1,16 @@
|
||||
/* eslint-env jest */
|
||||
describe('Sequencediagram', () => {
|
||||
it('should render a simple sequence diagrams', () => {
|
||||
const url = 'http://localhost:9000/webpackUsage.html';
|
||||
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('svg')
|
||||
.should('have.length', 1);
|
||||
cy.get('body').find('svg').should('have.length', 1);
|
||||
});
|
||||
it('should handle html escapings properly', () => {
|
||||
const url = 'http://localhost:9000/webpackUsage.html?test-html-escaping=true';
|
||||
|
||||
cy.visit(url);
|
||||
cy.get('body')
|
||||
.find('svg')
|
||||
.should('have.length', 1);
|
||||
cy.get('body').find('svg').should('have.length', 1);
|
||||
|
||||
cy.get('.label > g > foreignobject > div').should('not.contain.text', '<b>');
|
||||
cy.get('g.label > foreignobject > div').should('not.contain.text', '<b>');
|
||||
});
|
||||
});
|
||||
|
@ -1,35 +1,118 @@
|
||||
/* eslint-env jest */
|
||||
import { mermaidUrl } from '../../helpers/util.js';
|
||||
|
||||
/* eslint-disable */
|
||||
describe('XSS', () => {
|
||||
it('should handle xss in tags', () => {
|
||||
const str = 'eyJjb2RlIjoiXG5ncmFwaCBMUlxuICAgICAgQi0tPkQoPGltZyBvbmVycm9yPWxvY2F0aW9uPWBqYXZhc2NyaXB0XFx1MDAzYXhzc0F0dGFja1xcdTAwMjhkb2N1bWVudC5kb21haW5cXHUwMDI5YCBzcmM9eD4pOyIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In19';
|
||||
const str =
|
||||
'eyJjb2RlIjoiXG5ncmFwaCBMUlxuICAgICAgQi0tPkQoPGltZyBvbmVycm9yPWxvY2F0aW9uPWBqYXZhc2NyaXB0XFx1MDAzYXhzc0F0dGFja1xcdTAwMjhkb2N1bWVudC5kb21haW5cXHUwMDI5YCBzcmM9eD4pOyIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In19';
|
||||
|
||||
const url = mermaidUrl(str,{}, true);
|
||||
const url = mermaidUrl(str, {}, true);
|
||||
|
||||
cy.visit(url);
|
||||
cy.wait(1000).then(()=>{
|
||||
cy.wait(1000).then(() => {
|
||||
cy.get('.mermaid').should('exist');
|
||||
});
|
||||
cy.get('svg')
|
||||
// cy.percySnapshot()
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
})
|
||||
it('should handle xss in tags in non-html mode', () => {
|
||||
const str = 'eyJjb2RlIjoiXG5ncmFwaCBMUlxuICAgICAgQi0tPkQoPGltZyBvbmVycm9yPWxvY2F0aW9uPWBqYXZhc2NyaXB0XFx1MDAzYXhzc0F0dGFja1xcdTAwMjhkb2N1bWVudC5kb21haW5cXHUwMDI5YCBzcmM9eD4pOyIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0IiwiZmxvd2NoYXJ0Ijp7Imh0bWxMYWJlbHMiOmZhbHNlfX19';
|
||||
it('should not allow tags in the css', () => {
|
||||
const str =
|
||||
'eyJjb2RlIjoiJSV7aW5pdDogeyAnZm9udEZhbWlseSc6ICdcXFwiPjwvc3R5bGU-PGltZyBzcmM9eCBvbmVycm9yPXhzc0F0dGFjaygpPid9IH0lJVxuZ3JhcGggTFJcbiAgICAgQSAtLT4gQiIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0IiwiZmxvd2NoYXJ0Ijp7Imh0bWxMYWJlbHMiOmZhbHNlfX0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9';
|
||||
|
||||
const url = mermaidUrl(str,{
|
||||
"theme": "default",
|
||||
"flowchart": {
|
||||
"htmlMode": false
|
||||
}
|
||||
}, true);
|
||||
const url = mermaidUrl(
|
||||
str,
|
||||
{
|
||||
theme: 'default',
|
||||
flowchart: {
|
||||
htmlMode: false,
|
||||
},
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
cy.visit(url);
|
||||
// cy.get('svg')
|
||||
// cy.percySnapshot()
|
||||
cy.get('.malware').should('not.exist');
|
||||
cy.wait(1000).then(() => {
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
})
|
||||
})
|
||||
it('should handle xss in tags in non-html mode', () => {
|
||||
const str =
|
||||
'eyJjb2RlIjoiXG5ncmFwaCBMUlxuICAgICAgQi0tPkQoPGltZyBvbmVycm9yPWxvY2F0aW9uPWBqYXZhc2NyaXB0XFx1MDAzYXhzc0F0dGFja1xcdTAwMjhkb2N1bWVudC5kb21haW5cXHUwMDI5YCBzcmM9eD4pOyIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0IiwiZmxvd2NoYXJ0Ijp7Imh0bWxMYWJlbHMiOmZhbHNlfX19';
|
||||
|
||||
const url = mermaidUrl(
|
||||
str,
|
||||
{
|
||||
theme: 'default',
|
||||
flowchart: {
|
||||
htmlMode: false,
|
||||
},
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
cy.visit(url);
|
||||
cy.wait(1000);
|
||||
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
|
||||
it('should not allow changing the __proto__ attribute using config', () => {
|
||||
cy.visit('http://localhost:9000/xss2.html');
|
||||
cy.wait(1000);
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
it('should not allow maniplulating htmlLabels into a false positive', () => {
|
||||
cy.visit('http://localhost:9000/xss4.html');
|
||||
cy.wait(1000);
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
it('should not allow maniplulating antiscript to run javascript', () => {
|
||||
cy.visit('http://localhost:9000/xss5.html');
|
||||
cy.wait(1000);
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
it('should not allow maniplulating antiscript to run javascript using onerror', () => {
|
||||
cy.visit('http://localhost:9000/xss6.html');
|
||||
cy.wait(1000);
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
it('should not allow maniplulating antiscript to run javascript using onerror in state diagrams with dagre wrapper', () => {
|
||||
cy.visit('http://localhost:9000/xss8.html');
|
||||
cy.wait(1000);
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
it('should not allow maniplulating antiscript to run javascript using onerror in state diagrams with dagre d3', () => {
|
||||
cy.visit('http://localhost:9000/xss9.html');
|
||||
cy.wait(1000);
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
it('should not allow maniplulating antiscript to run javascript using onerror in state diagrams with dagre d3', () => {
|
||||
cy.visit('http://localhost:9000/xss10.html');
|
||||
cy.wait(1000);
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
it('should not allow maniplulating antiscript to run javascript using onerror in state diagrams with dagre d3', () => {
|
||||
cy.visit('http://localhost:9000/xss11.html');
|
||||
cy.wait(1000);
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
it('should not allow maniplulating antiscript to run javascript using onerror in state diagrams with dagre d3', () => {
|
||||
cy.visit('http://localhost:9000/xss12.html');
|
||||
cy.wait(1000);
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
it('should not allow maniplulating antiscript to run javascript using onerror in state diagrams with dagre d3', () => {
|
||||
cy.visit('http://localhost:9000/xss13.html');
|
||||
cy.wait(1000);
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
it('should not allow maniplulating antiscript to run javascript iframes in class diagrams', () => {
|
||||
cy.visit('http://localhost:9000/xss14.html');
|
||||
cy.wait(1000);
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
it('should sanitize cardinalities properly in class diagrams', () => {
|
||||
cy.visit('http://localhost:9000/xss18.html');
|
||||
cy.wait(1000);
|
||||
cy.get('#the-malware').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,8 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest } from '../../helpers/util';
|
||||
describe('Class diagram V2', () => {
|
||||
|
||||
it('0: should render a simple class diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
it('0: should render a simple class diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram-v2
|
||||
|
||||
classA -- classB : Inheritance
|
||||
@ -13,10 +11,10 @@ describe('Class diagram V2', () => {
|
||||
classB -- classD
|
||||
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('1: should render a simple class diagram', () => {
|
||||
imgSnapshotTest(
|
||||
@ -47,7 +45,7 @@ describe('Class diagram V2', () => {
|
||||
test()
|
||||
}
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -76,8 +74,7 @@ describe('Class diagram V2', () => {
|
||||
test()
|
||||
}
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -95,7 +92,7 @@ describe('Class diagram V2', () => {
|
||||
Class01 : +int publicGorilla
|
||||
Class01 : #int protectedMarmoset
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -103,7 +100,7 @@ describe('Class diagram V2', () => {
|
||||
it('should render multiple class diagrams', () => {
|
||||
imgSnapshotTest(
|
||||
[
|
||||
`
|
||||
`
|
||||
classDiagram-v2
|
||||
Class01 "1" <|--|> "*" AveryLongClass : Cool
|
||||
<<interface>> Class01
|
||||
@ -125,7 +122,7 @@ describe('Class diagram V2', () => {
|
||||
test()
|
||||
}
|
||||
`,
|
||||
`
|
||||
`
|
||||
classDiagram-v2
|
||||
Class01 "1" <|--|> "*" AveryLongClass : Cool
|
||||
<<interface>> Class01
|
||||
@ -148,7 +145,7 @@ describe('Class diagram V2', () => {
|
||||
}
|
||||
`,
|
||||
],
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -178,7 +175,7 @@ describe('Class diagram V2', () => {
|
||||
test()
|
||||
}
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -190,7 +187,7 @@ describe('Class diagram V2', () => {
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
Class01 : someMethod()*
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -202,7 +199,7 @@ describe('Class diagram V2', () => {
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
Class01 : someMethod()$
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -222,7 +219,7 @@ describe('Class diagram V2', () => {
|
||||
test()
|
||||
}
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -243,7 +240,7 @@ describe('Class diagram V2', () => {
|
||||
test()
|
||||
}
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -265,7 +262,7 @@ describe('Class diagram V2', () => {
|
||||
}
|
||||
link Class01 "google.com" "A Tooltip"
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -287,7 +284,7 @@ describe('Class diagram V2', () => {
|
||||
}
|
||||
callback Class01 "functionCall" "A Tooltip"
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -302,7 +299,7 @@ describe('Class diagram V2', () => {
|
||||
testArray() bool[]
|
||||
}
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -318,7 +315,7 @@ describe('Class diagram V2', () => {
|
||||
testArray() bool[]
|
||||
}
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -336,7 +333,7 @@ describe('Class diagram V2', () => {
|
||||
|
||||
cssClass "Class10" exClass2
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -352,7 +349,7 @@ describe('Class diagram V2', () => {
|
||||
testArray() bool[]
|
||||
}
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -366,7 +363,118 @@ describe('Class diagram V2', () => {
|
||||
|
||||
cssClass "Class10, class20" exClass2
|
||||
`,
|
||||
{logLevel : 1, flowchart: { "htmlLabels": false },}
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('16a: should render a simple class diagram with static field', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram-v2
|
||||
class Foo {
|
||||
+String bar$
|
||||
}
|
||||
`,
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('16b: should handle the direction statemnent with TB', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
direction TB
|
||||
class Student {
|
||||
-idCard : IdCard
|
||||
}
|
||||
class IdCard{
|
||||
-id : int
|
||||
-name : string
|
||||
}
|
||||
class Bike{
|
||||
-id : int
|
||||
-name : string
|
||||
}
|
||||
Student "1" --o "1" IdCard : carries
|
||||
Student "1" --o "1" Bike : rides
|
||||
|
||||
`,
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('18: should handle the direction statemnent with LR', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
direction LR
|
||||
class Student {
|
||||
-idCard : IdCard
|
||||
}
|
||||
class IdCard{
|
||||
-id : int
|
||||
-name : string
|
||||
}
|
||||
class Bike{
|
||||
-id : int
|
||||
-name : string
|
||||
}
|
||||
Student "1" --o "1" IdCard : carries
|
||||
Student "1" --o "1" Bike : rides
|
||||
|
||||
`,
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('17a: should handle the direction statemnent with BT', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
direction BT
|
||||
class Student {
|
||||
-idCard : IdCard
|
||||
}
|
||||
class IdCard{
|
||||
-id : int
|
||||
-name : string
|
||||
}
|
||||
class Bike{
|
||||
-id : int
|
||||
-name : string
|
||||
}
|
||||
Student "1" --o "1" IdCard : carries
|
||||
Student "1" --o "1" Bike : rides
|
||||
|
||||
`,
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('17b: should handle the direction statemment with RL', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
direction RL
|
||||
class Student {
|
||||
-idCard : IdCard
|
||||
}
|
||||
class IdCard{
|
||||
-id : int
|
||||
-name : string
|
||||
}
|
||||
class Bike{
|
||||
-id : int
|
||||
-name : string
|
||||
}
|
||||
Student "1" --o "1" IdCard : carries
|
||||
Student "1" --o "1" Bike : rides
|
||||
|
||||
`,
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
@ -1,406 +1,410 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util';
|
||||
|
||||
describe('Class diagram', () => {
|
||||
it('1: should render a simple class diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
int id
|
||||
test()
|
||||
}
|
||||
`,
|
||||
{logLevel : 1}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('2: should render a simple class diagrams with cardinality', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
Class01 "1" <|--|> "*" AveryLongClass : Cool
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
int id
|
||||
test()
|
||||
}
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('3: should render a simple class diagram with different visibilities', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
<<interface>> 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
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
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~ {
|
||||
<<service>>
|
||||
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~ {
|
||||
<<service>>
|
||||
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~ {
|
||||
<<service>>
|
||||
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~ {
|
||||
<<service>>
|
||||
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[]
|
||||
}
|
||||
|
||||
cssClass "Class10" exClass
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('14: should render a simple class diagram with css classes applied directly', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
class Class10:::exClass {
|
||||
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" exClass
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('16: should render multiple class diagrams', () => {
|
||||
imgSnapshotTest(
|
||||
[
|
||||
`
|
||||
classDiagram
|
||||
Class01 "1" <|--|> "*" AveryLongClass : Cool
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
int id
|
||||
test()
|
||||
}
|
||||
`,
|
||||
`
|
||||
classDiagram
|
||||
Class01 "1" <|--|> "*" AveryLongClass : Cool
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
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%');
|
||||
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(160 * .95, 160 * 1.05);
|
||||
});
|
||||
});
|
||||
|
||||
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(160 * .95, 160 * 1.05);
|
||||
expect(svg).to.have.attr('height', '218');
|
||||
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
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
int id
|
||||
test()
|
||||
}
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('2: should render a simple class diagrams with cardinality', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
Class01 "1" <|--|> "*" AveryLongClass : Cool
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
int id
|
||||
test()
|
||||
}
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('3: should render a simple class diagram with different visibilities', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
<<interface>> 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
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
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~ {
|
||||
<<service>>
|
||||
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~ {
|
||||
<<service>>
|
||||
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~ {
|
||||
<<service>>
|
||||
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~ {
|
||||
<<service>>
|
||||
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
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
int id
|
||||
test()
|
||||
}
|
||||
`,
|
||||
`
|
||||
classDiagram
|
||||
Class01 "1" <|--|> "*" AveryLongClass : Cool
|
||||
<<interface>> 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 {
|
||||
<<service>>
|
||||
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');
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
@ -1,10 +1,9 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest } from '../../helpers/util.js';
|
||||
|
||||
describe('Configuration and directives - nodes should be light blue', () => {
|
||||
it('No config - use default', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
it('No config - use default', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
graph TD
|
||||
A(Default) --> B[/Another/]
|
||||
A --> C[End]
|
||||
@ -13,13 +12,13 @@ describe('Configuration and directives - nodes should be light blue', () => {
|
||||
C
|
||||
end
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Settigns from intitialize - nodes should be green', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Settigns from intitialize - nodes should be green', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
graph TD
|
||||
A(Forest) --> B[/Another/]
|
||||
A --> C[End]
|
||||
@ -27,13 +26,13 @@ graph TD
|
||||
B
|
||||
C
|
||||
end `,
|
||||
{theme:'forest'}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Settings from initialize overriding themeVariable - nodes shold be red', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{ theme: 'forest' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Settings from initialize overriding themeVariable - nodes shold be red', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
|
||||
|
||||
%%{init: { 'theme': 'base', 'themeVariables':{ 'primaryColor': '#ff0000'}}}%%
|
||||
@ -45,13 +44,13 @@ graph TD
|
||||
C
|
||||
end
|
||||
`,
|
||||
{theme:'base', themeVariables:{ primaryColor: '#ff0000'}, logLevel: 0}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Settings from directive - nodes should be grey', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{ theme: 'base', themeVariables: { primaryColor: '#ff0000' }, logLevel: 0 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Settings from directive - nodes should be grey', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: { 'logLevel': 0, 'theme': 'neutral'} }%%
|
||||
graph TD
|
||||
A(Start) --> B[/Another/]
|
||||
@ -61,14 +60,14 @@ graph TD
|
||||
C
|
||||
end
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('Settings from directive overriding theme variable - nodes should be red', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
it('Settings from directive overriding theme variable - nodes should be red', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: {'theme': 'base', 'themeVariables':{ 'primaryColor': '#ff0000'}}}%%
|
||||
graph TD
|
||||
A(Start) --> B[/Another/]
|
||||
@ -78,13 +77,13 @@ graph TD
|
||||
C
|
||||
end
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Settings from initialize and directive - nodes should be grey', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
it('Settings from initialize and directive - nodes should be grey', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: { 'logLevel': 0, 'theme': 'neutral'} }%%
|
||||
graph TD
|
||||
A(Start) --> B[/Another/]
|
||||
@ -94,13 +93,13 @@ graph TD
|
||||
C
|
||||
end
|
||||
`,
|
||||
{theme:'forest'}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Theme from initialize, directive overriding theme variable - nodes should be red', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{ theme: 'forest' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Theme from initialize, directive overriding theme variable - nodes should be red', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: {'theme': 'base', 'themeVariables':{ 'primaryColor': '#ff0000'}}}%%
|
||||
graph TD
|
||||
A(Start) --> B[/Another/]
|
||||
@ -110,13 +109,13 @@ graph TD
|
||||
C
|
||||
end
|
||||
`,
|
||||
{theme:'base'}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Theme variable from initialize, theme from directive - nodes should be red', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
{ theme: 'base' }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('Theme variable from initialize, theme from directive - nodes should be red', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: { 'logLevel': 0, 'theme': 'base'} }%%
|
||||
graph TD
|
||||
A(Start) --> B[/Another/]
|
||||
@ -126,16 +125,16 @@ graph TD
|
||||
C
|
||||
end
|
||||
`,
|
||||
{themeVariables:{primaryColor: '#ff0000'}}
|
||||
);
|
||||
{ themeVariables: { primaryColor: '#ff0000' } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
describe('when rendering several diagrams', () => {
|
||||
it('diagrams should not taint later diagrams', () => {
|
||||
const url = 'http://localhost:9000/theme-directives.html';
|
||||
cy.visit(url);
|
||||
cy.get('svg');
|
||||
});
|
||||
describe('when rendering several diagrams', () => {
|
||||
it('diagrams should not taint later diagrams', () => {
|
||||
const url = 'http://localhost:9000/theme-directives.html';
|
||||
cy.visit(url);
|
||||
cy.get('svg');
|
||||
cy.percySnapshot();
|
||||
});
|
||||
cy.percySnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest } from '../../helpers/util';
|
||||
|
||||
describe('State diagram', () => {
|
||||
|
@ -1,14 +1,12 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest } from '../../helpers/util';
|
||||
|
||||
describe('Flowchart', () => {
|
||||
|
||||
it('34: testing the label width in percy', () => {
|
||||
imgSnapshotTest(
|
||||
`graph TD
|
||||
A[Christmas]
|
||||
`,
|
||||
{ theme: 'forest' , fontFamily: '"Noto Sans SC", sans-serif' }
|
||||
{ theme: 'forest', fontFamily: '"Noto Sans SC", sans-serif' }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util';
|
||||
|
||||
describe('Entity Relationship Diagram', () => {
|
||||
@ -9,7 +8,7 @@ describe('Entity Relationship Diagram', () => {
|
||||
CUSTOMER ||--o{ ORDER : places
|
||||
ORDER ||--|{ LINE-ITEM : contains
|
||||
`,
|
||||
{logLevel : 1}
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -22,7 +21,7 @@ describe('Entity Relationship Diagram', () => {
|
||||
CUSTOMER ||--o{ ORDER : places
|
||||
ORDER ||--|{ LINE-ITEM : contains
|
||||
`,
|
||||
{logLevel : 1}
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -34,7 +33,7 @@ describe('Entity Relationship Diagram', () => {
|
||||
CUSTOMER ||--|{ ADDRESS : "invoiced at"
|
||||
CUSTOMER ||--|{ ADDRESS : "receives goods at"
|
||||
`,
|
||||
{logLevel : 1}
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -47,7 +46,7 @@ describe('Entity Relationship Diagram', () => {
|
||||
B ||--|{ C : likes
|
||||
C ||--|{ A : likes
|
||||
`,
|
||||
{logLevel : 1}
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -65,7 +64,7 @@ describe('Entity Relationship Diagram', () => {
|
||||
PRODUCT-CATEGORY ||--|{ PRODUCT : contains
|
||||
PRODUCT ||--o{ ORDER-ITEM : "ordered in"
|
||||
`,
|
||||
{logLevel : 1}
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -73,18 +72,18 @@ describe('Entity Relationship Diagram', () => {
|
||||
it('should render multiple ER diagrams', () => {
|
||||
imgSnapshotTest(
|
||||
[
|
||||
`
|
||||
`
|
||||
erDiagram
|
||||
CUSTOMER ||--o{ ORDER : places
|
||||
ORDER ||--|{ LINE-ITEM : contains
|
||||
`,
|
||||
`
|
||||
`
|
||||
erDiagram
|
||||
CUSTOMER ||--o{ ORDER : places
|
||||
ORDER ||--|{ LINE-ITEM : contains
|
||||
`
|
||||
`,
|
||||
],
|
||||
{logLevel : 1}
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -97,7 +96,7 @@ describe('Entity Relationship Diagram', () => {
|
||||
BOOK }|..|{ GENRE : " "
|
||||
AUTHOR }|..|{ GENRE : " "
|
||||
`,
|
||||
{logLevel : 1}
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -111,16 +110,15 @@ describe('Entity Relationship Diagram', () => {
|
||||
`,
|
||||
{ er: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height', '465');
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(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(140 * .95, 140 * 1.05);
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height', '465');
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(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(140 * 0.95, 140 * 1.05);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render an ER when useMaxWidth is false', () => {
|
||||
@ -132,13 +130,114 @@ describe('Entity Relationship Diagram', () => {
|
||||
`,
|
||||
{ er: { 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(140 * .95, 140 * 1.05);
|
||||
expect(svg).to.have.attr('height', '465');
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
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(140 * 0.95, 140 * 1.05);
|
||||
expect(svg).to.have.attr('height', '465');
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
|
||||
it('should render entities that have no relationships', () => {
|
||||
renderGraph(
|
||||
`
|
||||
erDiagram
|
||||
DEAD_PARROT
|
||||
HERMIT
|
||||
RECLUSE
|
||||
SOCIALITE }o--o{ SOCIALITE : "interacts with"
|
||||
RECLUSE }o--o{ SOCIALITE : avoids
|
||||
`,
|
||||
{ er: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render entities with and without attributes', () => {
|
||||
renderGraph(
|
||||
`
|
||||
erDiagram
|
||||
BOOK { string title }
|
||||
AUTHOR }|..|{ BOOK : writes
|
||||
BOOK { float price }
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render entities and attributes with big and small entity names', () => {
|
||||
renderGraph(
|
||||
`
|
||||
erDiagram
|
||||
PRIVATE_FINANCIAL_INSTITUTION {
|
||||
string name
|
||||
int turnover
|
||||
}
|
||||
PRIVATE_FINANCIAL_INSTITUTION ||..|{ EMPLOYEE : employs
|
||||
EMPLOYEE { bool officer_of_firm }
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render entities with keys', () => {
|
||||
renderGraph(
|
||||
`
|
||||
erDiagram
|
||||
AUTHOR_WITH_LONG_ENTITY_NAME {
|
||||
string name PK
|
||||
}
|
||||
AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
|
||||
BOOK {
|
||||
float price
|
||||
string author FK
|
||||
string title PK
|
||||
}
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render entities with comments', () => {
|
||||
renderGraph(
|
||||
`
|
||||
erDiagram
|
||||
AUTHOR_WITH_LONG_ENTITY_NAME {
|
||||
string name "comment"
|
||||
}
|
||||
AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
|
||||
BOOK {
|
||||
string author
|
||||
string title "author comment"
|
||||
float price "price comment"
|
||||
}
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
|
||||
it('should render entities with keys and comments', () => {
|
||||
renderGraph(
|
||||
`
|
||||
erDiagram
|
||||
AUTHOR_WITH_LONG_ENTITY_NAME {
|
||||
string name PK "comment"
|
||||
}
|
||||
AUTHOR_WITH_LONG_ENTITY_NAME }|..|{ BOOK : writes
|
||||
BOOK {
|
||||
string description
|
||||
float price "price comment"
|
||||
string title PK "title comment"
|
||||
string author FK
|
||||
}
|
||||
`,
|
||||
{ logLevel: 1 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util';
|
||||
|
||||
describe('Flowchart v2', () => {
|
||||
@ -29,7 +28,7 @@ describe('Flowchart v2', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('3: a link with correct arrowhead to a subgraph', () => {
|
||||
it('3: a link with correct arrowhead to a subgraph', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart TD
|
||||
P1
|
||||
@ -69,7 +68,7 @@ describe('Flowchart v2', () => {
|
||||
`flowchart TD
|
||||
a["<strong>Haiya</strong>"]---->b
|
||||
`,
|
||||
{htmlLabels: false, flowchart: {htmlLabels: false}}
|
||||
{ htmlLabels: false, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
});
|
||||
it('6: should render non-escaped with html labels', () => {
|
||||
@ -77,7 +76,7 @@ describe('Flowchart v2', () => {
|
||||
`flowchart TD
|
||||
a["<strong>Haiya</strong>"]===>b
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('7: should render a flowchart when useMaxWidth is true (default)', () => {
|
||||
@ -91,18 +90,17 @@ describe('Flowchart v2', () => {
|
||||
`,
|
||||
{ flowchart: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.be.within(446 * .95, 446 * 1.05);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.be.within(300 * .95-1, 300 * 1.05);
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.be.within(290 * 0.95 - 1, 290 * 1.05);
|
||||
});
|
||||
});
|
||||
it('8: should render a flowchart when useMaxWidth is false', () => {
|
||||
renderGraph(
|
||||
@ -115,15 +113,14 @@ describe('Flowchart v2', () => {
|
||||
`,
|
||||
{ flowchart: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
expect(height).to.be.within(446 * .95, 446 * 1.05);
|
||||
expect(width).to.be.within(300 * .95-1, 300 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
||||
expect(width).to.be.within(290 * 0.95 - 1, 290 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
|
||||
it('V2 - 16: Render Stadium shape', () => {
|
||||
@ -141,7 +138,7 @@ describe('Flowchart v2', () => {
|
||||
class A someclass;
|
||||
class C someclass;
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -156,7 +153,7 @@ describe('Flowchart v2', () => {
|
||||
b
|
||||
end
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -171,7 +168,7 @@ describe('Flowchart v2', () => {
|
||||
b
|
||||
end
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -192,7 +189,7 @@ describe('Flowchart v2', () => {
|
||||
B
|
||||
end
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -222,7 +219,7 @@ describe('Flowchart v2', () => {
|
||||
routeur --> subnet1 & subnet2
|
||||
subnet1 & subnet2 --> nat --> internet
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -236,7 +233,7 @@ describe('Flowchart v2', () => {
|
||||
subcontainer-child--> subcontainer-sibling
|
||||
end
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -258,11 +255,10 @@ end
|
||||
sub_one --> sub_two
|
||||
_one --> b
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it('56: handle nested subgraphs with outgoing links 3', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart TB
|
||||
@ -275,7 +271,7 @@ _one --> b
|
||||
end
|
||||
process_B-->|via_AWSBatch|container_Beta
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('57: handle nested subgraphs with outgoing links 4', () => {
|
||||
@ -288,11 +284,10 @@ subgraph B
|
||||
b
|
||||
end
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it('57: handle nested subgraphs with outgoing links 2', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart TB
|
||||
@ -310,7 +305,23 @@ end
|
||||
three --> two
|
||||
two --> c2
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('57.x: handle nested subgraphs with outgoing links 5', () => {
|
||||
imgSnapshotTest(
|
||||
`%% this does not produce the desired result
|
||||
flowchart TB
|
||||
subgraph container_Beta
|
||||
process_C-->Process_D
|
||||
end
|
||||
subgraph container_Alpha
|
||||
process_A-->process_B
|
||||
process_B-->|via_AWSBatch|container_Beta
|
||||
process_A-->|messages|process_C
|
||||
end
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('58: handle styling with style expressions', () => {
|
||||
@ -321,7 +332,7 @@ end
|
||||
style id1 fill:#f9f,stroke:#333,stroke-width:4px
|
||||
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('59: handle styling of subgraphs and links', () => {
|
||||
@ -343,7 +354,37 @@ flowchart TD
|
||||
class T TestSub
|
||||
linkStyle 0,1 color:orange, stroke: orange;
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('60: handle styling for all node shapes - v2', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
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[\\ red text\\] -->|default style| L[/blue text\\]
|
||||
M[\\ red 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;
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', logLevel: 2 }
|
||||
);
|
||||
});
|
||||
it('61: fontawesome icons in edge labels', () => {
|
||||
@ -352,9 +393,260 @@ flowchart TD
|
||||
flowchart TD
|
||||
C -->|fa:fa-car Car| F[fa:fa-car Car]
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('62: should render styled subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart TB
|
||||
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
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('63: title on subgraphs should be themable', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%%
|
||||
flowchart LR
|
||||
subgraph A
|
||||
a --> b
|
||||
end
|
||||
subgraph B
|
||||
i -->f
|
||||
end
|
||||
A --> B
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('65: text-color from classes', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart LR
|
||||
classDef dark fill:#000,stroke:#000,stroke-width:4px,color:#fff
|
||||
Lorem --> Ipsum --> Dolor
|
||||
class Lorem,Dolor dark
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('66: More nested subgraph cases (TB)', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart TB
|
||||
subgraph two
|
||||
b1
|
||||
end
|
||||
subgraph three
|
||||
c2
|
||||
end
|
||||
|
||||
three --> two
|
||||
two --> c2
|
||||
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('67: More nested subgraph cases (RL)', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart RL
|
||||
subgraph two
|
||||
b1
|
||||
end
|
||||
subgraph three
|
||||
c2
|
||||
end
|
||||
|
||||
three --> two
|
||||
two --> c2
|
||||
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('68: More nested subgraph cases (BT)', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart BT
|
||||
subgraph two
|
||||
b1
|
||||
end
|
||||
subgraph three
|
||||
c2
|
||||
end
|
||||
|
||||
three --> two
|
||||
two --> c2
|
||||
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('69: More nested subgraph cases (LR)', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart LR
|
||||
subgraph two
|
||||
b1
|
||||
end
|
||||
subgraph three
|
||||
c2
|
||||
end
|
||||
|
||||
three --> two
|
||||
two --> c2
|
||||
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('70: Handle nested subgraph cases (TB) link out and link between subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart TB
|
||||
subgraph S1
|
||||
sub1 -->sub2
|
||||
end
|
||||
subgraph S2
|
||||
sub4
|
||||
end
|
||||
S1 --> S2
|
||||
sub1 --> sub4
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('71: Handle nested subgraph cases (RL) link out and link between subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart RL
|
||||
subgraph S1
|
||||
sub1 -->sub2
|
||||
end
|
||||
subgraph S2
|
||||
sub4
|
||||
end
|
||||
S1 --> S2
|
||||
sub1 --> sub4
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('72: Handle nested subgraph cases (BT) link out and link between subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart BT
|
||||
subgraph S1
|
||||
sub1 -->sub2
|
||||
end
|
||||
subgraph S2
|
||||
sub4
|
||||
end
|
||||
S1 --> S2
|
||||
sub1 --> sub4
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('74: Handle nested subgraph cases (RL) link out and link between subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart RL
|
||||
subgraph S1
|
||||
sub1 -->sub2
|
||||
end
|
||||
subgraph S2
|
||||
sub4
|
||||
end
|
||||
S1 --> S2
|
||||
sub1 --> sub4
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('74: Handle labels for multiple edges from and to the same couple of nodes', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart RL
|
||||
subgraph one
|
||||
a1 -- l1 --> a2
|
||||
a1 -- l2 --> a2
|
||||
end
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('76: handle unicode encoded character with HTML labels true', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart TB
|
||||
a{{"Lorem 'ipsum' dolor 'sit' amet, 'consectetur' adipiscing 'elit'."}}
|
||||
--> b{{"Lorem #quot;ipsum#quot; dolor #quot;sit#quot; amet,#quot;consectetur#quot; adipiscing #quot;elit#quot;."}}
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('2050: handling of different rendering direction in subgraphs', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart LR
|
||||
|
||||
subgraph TOP
|
||||
direction TB
|
||||
subgraph B1
|
||||
direction RL
|
||||
i1 -->f1
|
||||
end
|
||||
subgraph B2
|
||||
direction BT
|
||||
i2 -->f2
|
||||
end
|
||||
end
|
||||
A --> TOP --> B
|
||||
B1 --> B2
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
|
||||
it('2388: handling default in the node name', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart LR
|
||||
default-index.js --> dot.template.js
|
||||
index.js --> module-utl.js
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util';
|
||||
|
||||
describe('Flowchart', () => {
|
||||
describe('Graph', () => {
|
||||
it('1: should render a simple flowchart no htmlLabels', () => {
|
||||
imgSnapshotTest(
|
||||
`graph TD
|
||||
@ -38,7 +37,7 @@ describe('Flowchart', () => {
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[Car]
|
||||
`,
|
||||
{fontFamily: 'courier'}
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -53,7 +52,7 @@ describe('Flowchart', () => {
|
||||
C -->|Two| E[\\iPhone\\]
|
||||
C -->|Three| F[Car]
|
||||
`,
|
||||
{ fontFamily: 'courier'}
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -69,7 +68,7 @@ describe('Flowchart', () => {
|
||||
classDef processHead fill:#888888,color:white,font-weight:bold,stroke-width:3px,stroke:#001f3f
|
||||
class 1A,1B,D,E processHead
|
||||
`,
|
||||
{fontFamily: 'courier'}
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -98,7 +97,7 @@ describe('Flowchart', () => {
|
||||
35(SAM.CommonFA.PopulationFME)-->39(SAM.CommonFA.ChargeDetails)
|
||||
36(SAM.CommonFA.PremetricCost)-->39(SAM.CommonFA.ChargeDetails)
|
||||
`,
|
||||
{ fontFamily: 'courier' }
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -169,7 +168,7 @@ describe('Flowchart', () => {
|
||||
9a072290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002
|
||||
9a072290_1ec3_e711_8c5a_005056ad0002-->71082290_1ec3_e711_8c5a_005056ad0002
|
||||
`,
|
||||
{ fontFamily: 'courier' }
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -178,7 +177,7 @@ describe('Flowchart', () => {
|
||||
`
|
||||
graph TB;subgraph "number as labels";1;end;
|
||||
`,
|
||||
{ fontFamily: 'courier' }
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -190,7 +189,7 @@ describe('Flowchart', () => {
|
||||
a1-->a2
|
||||
end
|
||||
`,
|
||||
{ fontFamily: 'courier' }
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -202,7 +201,7 @@ describe('Flowchart', () => {
|
||||
a1-->a2
|
||||
end
|
||||
`,
|
||||
{ fontFamily: 'courier' }
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -234,10 +233,10 @@ describe('Flowchart', () => {
|
||||
B-->G
|
||||
G-->D
|
||||
|
||||
style foo fill:#F99,stroke-width:2px,stroke:#F0F
|
||||
style bar fill:#999,stroke-width:10px,stroke:#0F0
|
||||
style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred
|
||||
style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue
|
||||
`,
|
||||
{ fontFamily: 'courier' }
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -339,7 +338,7 @@ describe('Flowchart', () => {
|
||||
sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A;
|
||||
sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4FC27B48-A6F9-460A-A675-021F5854FE22;
|
||||
`,
|
||||
{ fontFamily: 'courier' }
|
||||
{ fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -357,7 +356,7 @@ describe('Flowchart', () => {
|
||||
listUrl: false,
|
||||
listId: 'color styling',
|
||||
fontFamily: 'courier',
|
||||
logLevel: 0
|
||||
logLevel: 0,
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -379,8 +378,9 @@ describe('Flowchart', () => {
|
||||
`,
|
||||
{
|
||||
listUrl: false,
|
||||
listId: 'color styling', fontFamily: 'courier',
|
||||
logLevel: 0
|
||||
listId: 'color styling',
|
||||
fontFamily: 'courier',
|
||||
logLevel: 0,
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -395,7 +395,7 @@ describe('Flowchart', () => {
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -414,7 +414,7 @@ describe('Flowchart', () => {
|
||||
class A someclass;
|
||||
class C someclass;
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -431,7 +431,7 @@ describe('Flowchart', () => {
|
||||
linkStyle 1 stroke:DarkGray,stroke-width:2px
|
||||
linkStyle 2 stroke:DarkGray,stroke-width:2px
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -440,7 +440,7 @@ describe('Flowchart', () => {
|
||||
`graph LR
|
||||
a --> b --> c
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -449,7 +449,7 @@ describe('Flowchart', () => {
|
||||
`graph LR
|
||||
a --> b & c--> d
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -459,7 +459,7 @@ describe('Flowchart', () => {
|
||||
A[ h ] -- hello --> B[" test "]:::exClass & C --> D;
|
||||
classDef exClass background:#bbb,border:1px solid red;
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -481,7 +481,7 @@ describe('Flowchart', () => {
|
||||
click B testClick "click test"
|
||||
classDef someclass fill:#f96;
|
||||
class A someclass;`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -522,7 +522,7 @@ describe('Flowchart', () => {
|
||||
linkStyle 1 stroke:greenyellow,stroke-width:2px
|
||||
style C fill:greenyellow,stroke:green,stroke-width:4px
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -545,7 +545,7 @@ describe('Flowchart', () => {
|
||||
click F "javascript:alert('test')" "script test"
|
||||
`,
|
||||
{ securityLevel: 'loose', fontFamily: 'courier' }
|
||||
);
|
||||
);
|
||||
});
|
||||
|
||||
it('26: Set text color of nodes and links according to styles when html labels are enabled', () => {
|
||||
@ -584,7 +584,7 @@ describe('Flowchart', () => {
|
||||
click B "index.html#link-clicked" "link test"
|
||||
click D testClick "click test"
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -616,7 +616,7 @@ describe('Flowchart', () => {
|
||||
class A myClass1
|
||||
class D myClass2
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -640,7 +640,7 @@ describe('Flowchart', () => {
|
||||
classDef redBg fill:#622;
|
||||
classDef whiteTxt color: white;
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -652,7 +652,7 @@ describe('Flowchart', () => {
|
||||
eat --> sleep
|
||||
work --> eat
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -671,7 +671,7 @@ describe('Flowchart', () => {
|
||||
class A someclass;
|
||||
class C someclass;
|
||||
`,
|
||||
{ flowchart: { htmlLabels: false } , fontFamily: 'courier'}
|
||||
{ flowchart: { htmlLabels: false }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@ -694,7 +694,7 @@ describe('Flowchart', () => {
|
||||
`graph TD
|
||||
A[Christmas]
|
||||
`,
|
||||
{ }
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
@ -712,7 +712,7 @@ describe('Flowchart', () => {
|
||||
C -----> E4
|
||||
C ======> E5
|
||||
`,
|
||||
{ }
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('36: should render escaped without html labels', () => {
|
||||
@ -720,7 +720,7 @@ describe('Flowchart', () => {
|
||||
`graph TD
|
||||
a["<strong>Haiya</strong>"]-->b
|
||||
`,
|
||||
{htmlLabels: false, flowchart: {htmlLabels: false}}
|
||||
{ htmlLabels: false, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
});
|
||||
it('37: should render non-escaped with html labels', () => {
|
||||
@ -728,7 +728,7 @@ describe('Flowchart', () => {
|
||||
`graph TD
|
||||
a["<strong>Haiya</strong>"]-->b
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('38: should render a flowchart when useMaxWidth is true (default)', () => {
|
||||
@ -742,18 +742,17 @@ describe('Flowchart', () => {
|
||||
`,
|
||||
{ flowchart: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.be.within(446 * .95, 446 * 1.05);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.be.within(300 * .95, 300 * 1.05);
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.be.within(300 * 0.95, 300 * 1.05);
|
||||
});
|
||||
});
|
||||
it('39: should render a flowchart when useMaxWidth is false', () => {
|
||||
renderGraph(
|
||||
@ -766,15 +765,14 @@ describe('Flowchart', () => {
|
||||
`,
|
||||
{ flowchart: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
expect(height).to.be.within(446 * .95, 446 * 1.05);
|
||||
expect(width).to.be.within(300 * .95, 300 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
||||
expect(width).to.be.within(300 * 0.95, 300 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
it('58: handle styling with style expressions', () => {
|
||||
imgSnapshotTest(
|
||||
@ -784,7 +782,31 @@ describe('Flowchart', () => {
|
||||
style id1 fill:#f9f,stroke:#333,stroke-width:4px
|
||||
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('60: handle styling for all node shapes', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
graph 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/]
|
||||
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
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('61: fontawesome icons in edge labels', () => {
|
||||
@ -793,8 +815,80 @@ describe('Flowchart', () => {
|
||||
graph TD
|
||||
C -->|fa:fa-car Car| F[fa:fa-car Car]
|
||||
`,
|
||||
{htmlLabels: true, flowchart: {htmlLabels: true}, securityLevel: 'loose'}
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('62: fontawesome icons in edge labels', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
graph TB
|
||||
subgraph bar[Bar]
|
||||
F
|
||||
end
|
||||
style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('63: fontawesome icons in edge labels', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
graph TB
|
||||
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
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('64: fontawesome icons in edge labels', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%%
|
||||
flowchart LR
|
||||
subgraph A
|
||||
a --> b
|
||||
end
|
||||
subgraph B
|
||||
i -->f
|
||||
end
|
||||
A --> B
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
it('65: text-color from classes', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart LR
|
||||
classDef dark fill:#000,stroke:#000,stroke-width:4px,color:#fff
|
||||
Lorem --> Ipsum --> Dolor
|
||||
class Lorem,Dolor dark
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,9 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js';
|
||||
|
||||
describe('Gantt diagram', () => {
|
||||
beforeEach(()=>{
|
||||
cy.clock((new Date('1010-10-10')).getTime())
|
||||
})
|
||||
beforeEach(() => {
|
||||
cy.clock(new Date('1010-10-10').getTime());
|
||||
});
|
||||
it('should render a gantt chart', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -199,18 +198,17 @@ describe('Gantt diagram', () => {
|
||||
`,
|
||||
{ gantt: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.be.within(484 * .95, 484 * 1.05);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.be.within(984 * .95, 984 * 1.05);
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.be.within(484 * 0.95, 484 * 1.05);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.be.within(984 * 0.95, 984 * 1.05);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render a gantt diagram when useMaxWidth is false', () => {
|
||||
@ -248,14 +246,49 @@ describe('Gantt diagram', () => {
|
||||
`,
|
||||
{ gantt: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
expect(height).to.be.within(484 * .95, 484 * 1.05);
|
||||
expect(width).to.be.within(984 * .95, 984 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
expect(height).to.be.within(484 * 0.95, 484 * 1.05);
|
||||
expect(width).to.be.within(984 * 0.95, 984 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
it('should render a gantt diagram with data labels at the top when topAxis is true', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
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 Last section
|
||||
Describe gantt syntax :after doc1, 3d
|
||||
Add gantt diagram to demo page : 20h
|
||||
Add another diagram to demo page : 48h
|
||||
`,
|
||||
{ gantt: { topAxis: true } }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest } from '../../helpers/util.js';
|
||||
|
||||
describe('Sequencediagram', () => {
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest } from '../../helpers/util.js';
|
||||
|
||||
describe('Sequencediagram', () => {
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js';
|
||||
|
||||
describe('User journey diagram', () => {
|
||||
@ -32,39 +31,36 @@ section Order from website
|
||||
it('should render a user journey diagram when useMaxWidth is true (default)', () => {
|
||||
renderGraph(
|
||||
`journey
|
||||
title Adding journey diagram functionality to mermaid
|
||||
title E-Commerce
|
||||
section Order from website
|
||||
Add to cart: 5: Me
|
||||
section Checkout from website
|
||||
Add payment details: 5: Me
|
||||
`,
|
||||
{ journey: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.eq(20);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.eq(400);
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.eq(565);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.eq(700);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render a user journey diagram when useMaxWidth is false', () => {
|
||||
renderGraph(
|
||||
imgSnapshotTest(
|
||||
`journey
|
||||
title Adding journey diagram functionality to mermaid
|
||||
title E-Commerce
|
||||
section Order from website
|
||||
Add to cart: 5: Me
|
||||
section Checkout from website
|
||||
Add payment details: 5: Me
|
||||
`,
|
||||
{ journey: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
expect(height).to.eq(20);
|
||||
expect(width).to.eq(400);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js';
|
||||
|
||||
describe('Pie Chart', () => {
|
||||
@ -47,17 +46,16 @@ describe('Pie Chart', () => {
|
||||
`,
|
||||
{ pie: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.eq(450);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.eq(984);
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.eq(450);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
expect(maxWidthValue).to.eq(984);
|
||||
});
|
||||
});
|
||||
it('should render a pie diagram when useMaxWidth is false', () => {
|
||||
renderGraph(
|
||||
@ -69,13 +67,12 @@ describe('Pie Chart', () => {
|
||||
`,
|
||||
{ pie: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
expect(height).to.eq(450);
|
||||
expect(width).to.eq(984);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
expect(height).to.eq(450);
|
||||
expect(width).to.eq(984);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
49
cypress/integration/rendering/requirement.spec.js
Normal file
49
cypress/integration/rendering/requirement.spec.js
Normal file
@ -0,0 +1,49 @@
|
||||
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');
|
||||
});
|
||||
});
|
@ -29,7 +29,7 @@ context('Sequence diagram', () => {
|
||||
Alice -->> John: Parallel message 2
|
||||
end
|
||||
`,
|
||||
{sequence:{actorFontFamily:'courier'}}
|
||||
{ sequence: { actorFontFamily: 'courier' } }
|
||||
);
|
||||
});
|
||||
it('should handle different line breaks', () => {
|
||||
@ -52,6 +52,26 @@ context('Sequence diagram', () => {
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should handle line breaks and wrap annotations', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant John as John<br/>Second Line
|
||||
Alice ->> Bob: Hello Bob, how are you?
|
||||
Bob-->>John: How about you John?
|
||||
Note right of John: John thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.
|
||||
Bob-->Alice: Checking with John...
|
||||
Note over John:wrap: John looks like he's still thinking, so Bob prods him a bit.
|
||||
Bob-x John: Hey John -<br/>we're still waiting to know<br/>how you're doing
|
||||
Note over John:nowrap: John's trying hard not to break his train of thought.
|
||||
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.
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should render loops with a slight margin', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -127,7 +147,7 @@ context('Sequence diagram', () => {
|
||||
A->>Bob: Hola
|
||||
Bob-->A: Pasten !
|
||||
`,
|
||||
{logLevel: 0}
|
||||
{ logLevel: 0 }
|
||||
);
|
||||
});
|
||||
it('should wrap (inline) long actor descriptions', () => {
|
||||
@ -138,7 +158,7 @@ context('Sequence diagram', () => {
|
||||
A->>Bob: Hola
|
||||
Bob-->A: Pasten !
|
||||
`,
|
||||
{logLevel: 0}
|
||||
{ logLevel: 0 }
|
||||
);
|
||||
});
|
||||
it('should wrap (directive) long actor descriptions', () => {
|
||||
@ -153,6 +173,18 @@ context('Sequence diagram', () => {
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should be possible to use actor symbols instead of boxes', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
actor Alice
|
||||
actor Bob
|
||||
Alice->>Bob: Hi Bob
|
||||
Bob->>Alice: Hi Alice
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should render long notes left of actor', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -495,17 +527,17 @@ context('Sequence diagram', () => {
|
||||
});
|
||||
it('should render with an init directive', () => {
|
||||
imgSnapshotTest(
|
||||
`%%{init: { "theme": "dark", 'config': { "fontFamily": "Menlo", "fontSize": 18, "fontWeight": 400, "wrap": true }}}%%
|
||||
`%%{init: { "theme": "dark", 'config': { "fontFamily": "Menlo", "fontSize": 18, "fontWeight": 400, "wrap": true }}}%%
|
||||
sequenceDiagram
|
||||
Alice->>Bob: Hello Bob, how are you? If you are not available right now, I can leave you a message. Please get back to me as soon as you can!
|
||||
Note left of Alice: Bob thinks
|
||||
Bob->>Alice: Fine!`,
|
||||
{}
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
context('directives', () => {
|
||||
it('should override config with directive settings', () => {
|
||||
it('should override config with directive settings', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: { "config": { "mirrorActors": true }}}%%
|
||||
@ -514,10 +546,13 @@ context('Sequence diagram', () => {
|
||||
note left of Alice: config set to mirrorActors: false<br/>directive set to mirrorActors: true
|
||||
Bob->>Alice: Short as well
|
||||
`,
|
||||
{ logLevel:0, sequence: { mirrorActors: false, noteFontSize: 18, noteFontFamily: 'Arial' } }
|
||||
{
|
||||
logLevel: 0,
|
||||
sequence: { mirrorActors: false, noteFontSize: 18, noteFontFamily: 'Arial' },
|
||||
}
|
||||
);
|
||||
});
|
||||
it('should override config with directive settings', () => {
|
||||
it('should override config with directive settings', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: { "config": { "mirrorActors": false, "wrap": true }}}%%
|
||||
@ -526,7 +561,53 @@ context('Sequence diagram', () => {
|
||||
note left of Alice: config: mirrorActors=true<br/>directive: mirrorActors=false
|
||||
Bob->>Alice: Short as well
|
||||
`,
|
||||
{ logLevel:0, sequence: { mirrorActors: true, noteFontSize: 18, noteFontFamily: 'Arial' } }
|
||||
{ logLevel: 0, sequence: { mirrorActors: true, noteFontSize: 18, noteFontFamily: 'Arial' } }
|
||||
);
|
||||
});
|
||||
});
|
||||
context('links', () => {
|
||||
it('should support actor links and properties EXPERIMENTAL: USE WITH CAUTION', () => {
|
||||
//Be aware that the syntax for "properties" is likely to be changed.
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: { "config": { "mirrorActors": true, "forceMenus": true }}}%%
|
||||
sequenceDiagram
|
||||
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!
|
||||
`,
|
||||
{ logLevel: 0, sequence: { mirrorActors: true, noteFontSize: 18, noteFontFamily: 'Arial' } }
|
||||
);
|
||||
});
|
||||
it('should support actor links and properties when not mirrored EXPERIMENTAL: USE WITH CAUTION', () => {
|
||||
//Be aware that the syntax for "properties" is likely to be changed.
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: { "config": { "mirrorActors": false, "forceMenus": true, "wrap": true }}}%%
|
||||
sequenceDiagram
|
||||
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"}
|
||||
a->>j: Hello John, how are you?
|
||||
j-->>a: Great!
|
||||
`,
|
||||
{
|
||||
logLevel: 0,
|
||||
sequence: { mirrorActors: false, noteFontSize: 18, noteFontFamily: 'Arial' },
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -559,18 +640,17 @@ context('Sequence diagram', () => {
|
||||
`,
|
||||
{ sequence: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.eq(920);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(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(820 * .95, 820 * 1.05);
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
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);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(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(820 * 0.95, 820 * 1.05);
|
||||
});
|
||||
});
|
||||
it('should render a sequence diagram when useMaxWidth is false', () => {
|
||||
renderGraph(
|
||||
@ -600,15 +680,14 @@ context('Sequence diagram', () => {
|
||||
`,
|
||||
{ sequence: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
expect(height).to.eq(920);
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
expect(width).to.be.within(820 * .95, 820 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
expect(height).to.be.within(920, 960);
|
||||
// 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');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util';
|
||||
|
||||
describe('State diagram', () => {
|
||||
@ -329,6 +328,49 @@ describe('State diagram', () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
it('v2 it should be possibel to use a choice', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
stateDiagram-v2
|
||||
[*] --> Off
|
||||
Off --> On
|
||||
state MyChoice [[choice]]
|
||||
On --> MyChoice
|
||||
MyChoice --> Washing
|
||||
MyChoice --> Drying
|
||||
Washing --> Finished
|
||||
Finished --> [*]
|
||||
`,
|
||||
{
|
||||
logLevel: 0,
|
||||
}
|
||||
);
|
||||
});
|
||||
it('v2 width of compond state should grow with title if title is wider', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
stateDiagram-v2
|
||||
state "Long state name 2" as NotShooting {
|
||||
a-->b
|
||||
}
|
||||
`,
|
||||
{
|
||||
logLevel: 0,
|
||||
}
|
||||
);
|
||||
});
|
||||
it('v2 state label with names in it', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
stateDiagram-v2
|
||||
Yswsii: Your state with spaces in it
|
||||
[*] --> Yswsii
|
||||
`,
|
||||
{
|
||||
logLevel: 0,
|
||||
}
|
||||
);
|
||||
});
|
||||
it('v2 Simplest composite state', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -338,7 +380,8 @@ describe('State diagram', () => {
|
||||
}
|
||||
`,
|
||||
{
|
||||
logLevel: 0, fontFamily: 'courier'
|
||||
logLevel: 0,
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -350,7 +393,63 @@ describe('State diagram', () => {
|
||||
a --> b: Stop
|
||||
`,
|
||||
{
|
||||
logLevel: 0, fontFamily: 'courier',
|
||||
logLevel: 0,
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
);
|
||||
});
|
||||
it('v2 should handle multiple notes added to one state', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
stateDiagram-v2
|
||||
MyState
|
||||
note left of MyState : I am a leftie
|
||||
note right of MyState : I am a rightie
|
||||
`,
|
||||
{
|
||||
logLevel: 0,
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
);
|
||||
});
|
||||
it('v2 should handle different rendering directions in composite states', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
stateDiagram-v2
|
||||
direction LR
|
||||
state A {
|
||||
direction BT
|
||||
a --> b
|
||||
}
|
||||
state C {
|
||||
direction RL
|
||||
c --> d
|
||||
}
|
||||
A --> C
|
||||
`,
|
||||
{
|
||||
logLevel: 0,
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
);
|
||||
});
|
||||
it('v2 handle transition from one state in a composite state to a composite state', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
stateDiagram-v2
|
||||
state S1 {
|
||||
sub1 -->sub2
|
||||
}
|
||||
|
||||
state S2 {
|
||||
sub4
|
||||
}
|
||||
S1 --> S2
|
||||
sub1 --> sub4
|
||||
`,
|
||||
{
|
||||
logLevel: 0,
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -364,18 +463,17 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ state: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.eq(177);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(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(135 * .95, 135 * 1.05);
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.be.within(177, 178);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(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(135 * 0.95, 135 * 1.05);
|
||||
});
|
||||
});
|
||||
it('v2 should render a state diagram when useMaxWidth is false', () => {
|
||||
renderGraph(
|
||||
@ -387,14 +485,13 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ state: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
expect(height).to.eq(177);
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
expect(width).to.be.within(135 * .95, 135 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
expect(height).to.be.within(177, 178);
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
expect(width).to.be.within(135 * 0.95, 135 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util';
|
||||
|
||||
describe('State diagram', () => {
|
||||
@ -315,7 +314,8 @@ describe('State diagram', () => {
|
||||
}
|
||||
`,
|
||||
{
|
||||
logLevel: 0, fontFamily: 'courier'
|
||||
logLevel: 0,
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -328,7 +328,8 @@ describe('State diagram', () => {
|
||||
}
|
||||
`,
|
||||
{
|
||||
logLevel: 0, fontFamily: 'courier'
|
||||
logLevel: 0,
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -340,7 +341,8 @@ describe('State diagram', () => {
|
||||
a --> b: Stop
|
||||
`,
|
||||
{
|
||||
logLevel: 0, fontFamily: 'courier'
|
||||
logLevel: 0,
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -353,18 +355,19 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ state: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.eq(139);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(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(112 * .95, 112 * 1.05);
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
expect(svg).to.have.attr('height');
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
expect(height).to.be.within(176, 178);
|
||||
const style = svg.attr('style');
|
||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
// Todo investigate difference
|
||||
// expect(maxWidthValue).to.be.within(112 * .95, 112 * 1.05);
|
||||
expect(maxWidthValue).to.be.within(130, 140);
|
||||
});
|
||||
});
|
||||
it('should render a state diagram when useMaxWidth is false', () => {
|
||||
renderGraph(
|
||||
@ -375,14 +378,16 @@ describe('State diagram', () => {
|
||||
`,
|
||||
{ state: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg')
|
||||
.should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
expect(height).to.eq(139);
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
expect(width).to.be.within(112 * .95, 112 * 1.05);
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
cy.get('svg').should((svg) => {
|
||||
const height = parseFloat(svg.attr('height'));
|
||||
const width = parseFloat(svg.attr('width'));
|
||||
expect(height).to.be.within(176, 178);
|
||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
||||
// Todo investigate difference
|
||||
// expect(width).to.be.within(112 * .95, 112 * 1.05);
|
||||
expect(width).to.be.within(130, 140);
|
||||
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,12 +1,36 @@
|
||||
/* eslint-env jest */
|
||||
import { imgSnapshotTest } from '../../helpers/util.js';
|
||||
|
||||
describe('Pie Chart', () => {
|
||||
// beforeEach(()=>{
|
||||
// cy.clock((new Date('2014-06-09')).getTime());
|
||||
// });
|
||||
describe('themeCSS balancing, it', () => {
|
||||
it('should not allow unbalanced CSS definitions', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: { 'themeCSS': '} * { background: red }' } }%%
|
||||
flowchart TD
|
||||
a --> b
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should not allow unbalanced CSS definitions 2', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: { 'themeCSS': '\u007D * { background: red }' } }%%
|
||||
flowchart TD
|
||||
a2 --> b2
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
|
||||
['default', 'forest', 'dark', 'neutral'].forEach(theme=>{
|
||||
describe('Pie Chart', () => {
|
||||
// beforeEach(()=>{
|
||||
// cy.clock((new Date('2014-06-09')).getTime());
|
||||
// });
|
||||
|
||||
['default', 'forest', 'dark', 'neutral'].forEach((theme) => {
|
||||
describe(theme, () => {
|
||||
it('should render a pie diagram', () => {
|
||||
imgSnapshotTest(
|
||||
@ -16,7 +40,7 @@ describe('Pie Chart', () => {
|
||||
"Ice-Hockey" : 80
|
||||
"Football" : 90
|
||||
`,
|
||||
{theme}
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -39,7 +63,7 @@ describe('Pie Chart', () => {
|
||||
G
|
||||
end
|
||||
`,
|
||||
{theme}
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -62,7 +86,7 @@ describe('Pie Chart', () => {
|
||||
G
|
||||
end
|
||||
`,
|
||||
{theme}
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -88,7 +112,7 @@ describe('Pie Chart', () => {
|
||||
|
||||
|
||||
`,
|
||||
{theme}
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
@ -135,10 +159,10 @@ describe('Pie Chart', () => {
|
||||
classM ..|> classN : Realization
|
||||
classO .. classP : Link(Dashed)
|
||||
`,
|
||||
{theme}
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
it('should render a state diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -167,10 +191,10 @@ stateDiagram
|
||||
Active --> SomethingElse
|
||||
note right of SomethingElse : This is the note to the right.
|
||||
`,
|
||||
{theme}
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
it('should render a state diagram (v2)', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -199,10 +223,10 @@ stateDiagram-v2
|
||||
Active --> SomethingElse2
|
||||
note right of SomethingElse2 : This is the note to the right.
|
||||
`,
|
||||
{theme}
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
it('should render a er diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -217,10 +241,10 @@ erDiagram
|
||||
PRODUCT ||--o{ ORDER-ITEM : "ordered in"
|
||||
|
||||
`,
|
||||
{theme}
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
it('should render a user journey diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -235,12 +259,12 @@ erDiagram
|
||||
Go downstairs: 5: Me
|
||||
Sit down: 5: Me
|
||||
`,
|
||||
{theme}
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
it('should render a gantt diagram', () => {
|
||||
cy.clock((new Date('2014-01-06')).getTime());
|
||||
cy.clock(new Date('2014-01-06').getTime());
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
@ -271,10 +295,10 @@ erDiagram
|
||||
Add gantt diagram to demo page :20h
|
||||
Add another diagram to demo page :48h
|
||||
`,
|
||||
{theme}
|
||||
{ theme }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -36,23 +36,23 @@ mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
securityLevel: 'loose',
|
||||
flowchart: {
|
||||
htmlLabels: true
|
||||
htmlLabels: true,
|
||||
},
|
||||
gantt: {
|
||||
axisFormatter: [
|
||||
[
|
||||
'%Y-%m-%d',
|
||||
d => {
|
||||
(d) => {
|
||||
return d.getDay() === 1;
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
});
|
||||
mermaid.render(
|
||||
'the-id-of-the-svg',
|
||||
code,
|
||||
svg => {
|
||||
(svg) => {
|
||||
console.log(svg);
|
||||
const elem = document.querySelector('#graph-to-be');
|
||||
elem.innerHTML = svg;
|
||||
|
@ -35,7 +35,7 @@
|
||||
+withdrawl(amount) int
|
||||
}
|
||||
cssClass "BankAccount" customCss
|
||||
|
||||
|
||||
</div>
|
||||
<div class="mermaid" style="width: 100%; height: 20%;">
|
||||
%%{init: {'theme': 'base', 'fontFamily': 'courier', 'themeVariables': { 'primaryColor': '#fff000'}}}%%
|
||||
@ -47,7 +47,7 @@
|
||||
+withdrawl(amount) int
|
||||
}
|
||||
cssClass "BankAccount" customCss
|
||||
|
||||
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%; height: 20%;">
|
||||
%%{init: {'theme': 'base', 'fontFamily': 'courier', 'themeVariables': { 'primaryColor': '#fff000'}}}%%
|
||||
@ -69,8 +69,8 @@
|
||||
int id
|
||||
test()
|
||||
}
|
||||
callback Class01 "callback" "A Tooltip"
|
||||
|
||||
callback Class01 "callback" "A Tooltip"
|
||||
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%; height: 20%;">
|
||||
flowchart TB
|
||||
@ -79,7 +79,7 @@
|
||||
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
|
||||
class a_a apa;
|
||||
click a_a "http://www.aftonbladet.se" "apa"
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mermaid2" style="width: 100%; height: 20%;">
|
||||
@ -110,19 +110,19 @@
|
||||
|
||||
class Shape
|
||||
callback Shape "callbackFunction" "This is a tooltip for a callback"
|
||||
|
||||
|
||||
</div>
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
mermaid.parseError = function (err, hash) {
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
theme: 'default',
|
||||
// arrowMarkerAbsolute: true,
|
||||
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
|
||||
logLevel: 0,
|
||||
flowchart: { curve: 'linear', "htmlLabels": true },
|
||||
flowchart: { curve: 'linear', htmlLabels: true },
|
||||
// gantt: { axisFormat: '%m/%d/%Y' },
|
||||
sequence: { actorMargin: 50, showSequenceNumbers: true },
|
||||
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||
@ -131,9 +131,11 @@
|
||||
// fontFamily: '"arial", sans-serif',
|
||||
// },
|
||||
curve: 'linear',
|
||||
securityLevel: 'loose'
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
function callback(){alert('It worked');}
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -95,35 +95,74 @@
|
||||
Add gantt diagram to demo page : 20h
|
||||
Add another diagram to demo page : 48h
|
||||
</div>
|
||||
<div style="display: flex">
|
||||
<div id="FirstLine" class="mermaid">
|
||||
graph TB
|
||||
FunctionArg-->URL
|
||||
click FunctionArg call clickByFlowArg(ARGUMENT) "Add a div"
|
||||
click URL "http://localhost:9000/webpackUsage.html" "Visit <strong>mermaid docs</strong>"
|
||||
</div>
|
||||
<div id="FirstLine" class="mermaid">
|
||||
flowchart TB
|
||||
FunctionArg-->URL
|
||||
click FunctionArg call clickByFlowArg(ARGUMENT) "Add a div"
|
||||
click URL "http://localhost:9000/webpackUsage.html" "Visit <strong>mermaid docs</strong>"
|
||||
</div>
|
||||
|
||||
<div id="FirstLine" class="mermaid">
|
||||
classDiagram
|
||||
class ShapeLink
|
||||
link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link"
|
||||
class ShapeCallback
|
||||
click ShapeCallback call clickByClass(123) "This is a tooltip for a callback"
|
||||
</div>
|
||||
|
||||
<div id="FirstLine" class="mermaid">
|
||||
classDiagram-v2
|
||||
class ShapeLink2
|
||||
link ShapeLink2 "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link"
|
||||
class ShapeCallback2
|
||||
click ShapeCallback2 call clickByClass(123) "This is a tooltip for a callback"
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
function clickByFlow(elemName) {
|
||||
const div = document.createElement('div')
|
||||
div.className = 'created-by-click'
|
||||
div.style = 'padding: 20px; background: green; color: white;'
|
||||
div.innerText = 'Clicked By Flow'
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-click';
|
||||
div.style = 'padding: 20px; background: green; color: white;';
|
||||
div.innerText = 'Clicked By Flow';
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div)
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
function clickByFlowArg(argument) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-click-2';
|
||||
div.style = 'padding: 20px; background: green; color: white;';
|
||||
div.innerText = 'Clicked By Flow: ' + argument;
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
function clickByGantt(arg1, arg2, arg3) {
|
||||
const div = document.createElement('div')
|
||||
div.className = 'created-by-gant-click'
|
||||
div.style = 'padding: 20px; background: green; color: white;'
|
||||
div.innerText = 'Clicked By Gant'
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-gant-click';
|
||||
div.style = 'padding: 20px; background: green; color: white;';
|
||||
div.innerText = 'Clicked By Gant';
|
||||
if (arg1) div.innerText += ' ' + arg1;
|
||||
if (arg2) div.innerText += ' ' + arg2;
|
||||
if (arg3) div.innerText += ' ' + arg3;
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div)
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
function clickByClass() {
|
||||
const div = document.createElement('div')
|
||||
div.className = 'created-by-class-click'
|
||||
div.style = 'padding: 20px; background: purple; color: white;'
|
||||
div.innerText = 'Clicked By Class'
|
||||
function clickByClass(arg) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-class-click';
|
||||
div.style = 'padding: 20px; background: purple; color: white;';
|
||||
div.innerText = 'Clicked By Class' + (arg ? arg : '');
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div)
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
mermaid.initialize({ startOnLoad: true, securityLevel: 'loose', logLevel: 1 });
|
||||
</script>
|
||||
|
@ -62,20 +62,20 @@
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
function clickByFlow(elemName) {
|
||||
const div = document.createElement('div')
|
||||
div.className = 'created-by-click'
|
||||
div.style = 'padding: 20px; background: green; color: white;'
|
||||
div.innerText = 'Clicked By Flow'
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-click';
|
||||
div.style = 'padding: 20px; background: green; color: white;';
|
||||
div.innerText = 'Clicked By Flow';
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div)
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
function clickByGantt(elemName) {
|
||||
const div = document.createElement('div')
|
||||
div.className = 'created-by-gant-click'
|
||||
div.style = 'padding: 20px; background: green; color: white;'
|
||||
div.innerText = 'Clicked By Gant'
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-gant-click';
|
||||
div.style = 'padding: 20px; background: green; color: white;';
|
||||
div.innerText = 'Clicked By Gant';
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div)
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
mermaid.initialize({ startOnLoad: true, securityLevel: 'strct', logLevel: 1 });
|
||||
</script>
|
||||
|
@ -64,23 +64,23 @@
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
function clickByFlow(elemName) {
|
||||
const div = document.createElement('div')
|
||||
div.className = 'created-by-click'
|
||||
div.style = 'padding: 20px; background: green; color: white;'
|
||||
div.innerText = 'Clicked By Flow'
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-click';
|
||||
div.style = 'padding: 20px; background: green; color: white;';
|
||||
div.innerText = 'Clicked By Flow';
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div)
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
function clickByGantt(arg1, arg2, arg3) {
|
||||
const div = document.createElement('div')
|
||||
div.className = 'created-by-gant-click'
|
||||
div.style = 'padding: 20px; background: green; color: white;'
|
||||
div.innerText = 'Clicked By Gant'
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-gant-click';
|
||||
div.style = 'padding: 20px; background: green; color: white;';
|
||||
div.innerText = 'Clicked By Gant';
|
||||
if (arg1) div.innerText += ' ' + arg1;
|
||||
if (arg2) div.innerText += ' ' + arg2;
|
||||
if (arg3) div.innerText += ' ' + arg3;
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div)
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
mermaid.initialize({ startOnLoad: true, securityLevel: 'strict', logLevel: 1 });
|
||||
</script>
|
||||
|
39
cypress/platform/css1.html
Normal file
39
cypress/platform/css1.html
Normal file
@ -0,0 +1,39 @@
|
||||
<!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>
|
||||
body {
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="mermaid2">
|
||||
%%{init: { 'themeCSS': '} * { background: lightblue }' } }%%
|
||||
flowchart TD
|
||||
a --> b
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
%%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%%
|
||||
flowchart LR
|
||||
subgraph A
|
||||
a --> b
|
||||
end
|
||||
subgraph B
|
||||
i -->f
|
||||
end
|
||||
A --> B
|
||||
</div>
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
function showFullFirstSquad(elemName) {
|
||||
console.log('show ' + elemName);
|
||||
}
|
||||
mermaid.initialize({ startOnLoad: true, securityLevel: 'loose', logLevel: 0 });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -74,7 +74,7 @@ stateDiagram-v2
|
||||
A --> D: asd123
|
||||
</div>
|
||||
</div>
|
||||
<div class="mermaid" style="width: 50%; height: 40%;">
|
||||
<div class="mermaid2" style="width: 50%; height: 40%;">
|
||||
%% this does not produce the desired result
|
||||
flowchart TB
|
||||
subgraph container_Beta
|
||||
@ -88,24 +88,13 @@ flowchart TB
|
||||
|
||||
</div>
|
||||
<div class="mermaid" style="width: 50%; height: 40%;">
|
||||
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#ff0000'}}}%%
|
||||
flowchart TB
|
||||
b-->B
|
||||
a-->c
|
||||
subgraph O
|
||||
A
|
||||
end
|
||||
subgraph B
|
||||
c
|
||||
end
|
||||
subgraph A
|
||||
a
|
||||
b
|
||||
B
|
||||
end
|
||||
flowchart TB
|
||||
a{{"Lorem 'ipsum' dolor 'sit' amet, 'consectetur' adipiscing 'elit'."}}
|
||||
--> b{{"Lorem #quot;ipsum#quot; dolor #quot;sit#quot; amet,#quot;consectetur#quot; adipiscing #quot;elit#quot;."}}
|
||||
|
||||
|
||||
</div>
|
||||
<div class="mermaid" style="width: 50%; height: 50%;">
|
||||
<div class="mermaid2" style="width: 50%; height: 50%;">
|
||||
flowchart TB
|
||||
internet
|
||||
nat
|
||||
@ -130,7 +119,7 @@ flowchart TB
|
||||
routeur --> subnet1 & subnet2
|
||||
subnet1 & subnet2 --> nat --> internet
|
||||
</div>
|
||||
<div class="mermaid" style="width: 50%; height: 50%;">
|
||||
<div class="mermaid2" style="width: 50%; height: 50%;">
|
||||
flowchart TD
|
||||
|
||||
subgraph one[One]
|
||||
@ -145,7 +134,7 @@ end
|
||||
|
||||
sub_one --> two
|
||||
</div>
|
||||
<div class="mermaid" style="width: 50%; height: 50%;">
|
||||
<div class="mermaid2" style="width: 50%; height: 50%;">
|
||||
flowchart TD
|
||||
|
||||
subgraph one[One]
|
||||
@ -166,23 +155,25 @@ _one --> b
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
mermaid.parseError = function (err, hash) {
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
// theme: 'forest',
|
||||
// themeVariables:{primaryColor: '#ff0000'},
|
||||
// arrowMarkerAbsolute: true,
|
||||
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
|
||||
logLevel: 0,
|
||||
flowchart: { curve: 'cardinal', "htmlLabels": false },
|
||||
flowchart: { curve: 'cardinal', htmlLabels: true },
|
||||
// gantt: { axisFormat: '%m/%d/%Y' },
|
||||
sequence: { actorMargin: 50, showSequenceNumbers: true },
|
||||
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||
fontFamily: '"arial", sans-serif',
|
||||
curve: 'cardinal',
|
||||
securityLevel: 'strict'
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
function callback(){alert('It worked');}
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -107,23 +107,25 @@ Note over Bob,Alice: Looks back
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
mermaid.parseError = function (err, hash) {
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
// theme: 'forest',
|
||||
// themeVariables:{primaryColor: '#ff0000'},
|
||||
// arrowMarkerAbsolute: true,
|
||||
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
|
||||
logLevel: 0,
|
||||
flowchart: { curve: 'cardinal', "htmlLabels": false },
|
||||
flowchart: { curve: 'cardinal', htmlLabels: false },
|
||||
// gantt: { axisFormat: '%m/%d/%Y' },
|
||||
sequence: { actorMargin: 50, showSequenceNumbers: true },
|
||||
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||
fontFamily: '"arial", sans-serif',
|
||||
curve: 'cardinal',
|
||||
securityLevel: 'strict'
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
function callback(){alert('It worked');}
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,52 +1,52 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<!-- <meta charset="iso-8859-15"/> -->
|
||||
<script src="/e2e.js"></script>
|
||||
<!-- <link href="https://fonts.googleapis.com/css?family=Mansalva&display=swap" rel="stylesheet" /> -->
|
||||
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
/* font-family: 'Mansalva', cursive;*/
|
||||
/* font-family: 'Mansalva', cursive; */
|
||||
/* font-family: 'arial'; */
|
||||
/* font-family: "trebuchet ms", verdana, arial; */
|
||||
}
|
||||
/* div {
|
||||
font-family: 'arial';
|
||||
} */
|
||||
/* .mermaid-main-font {
|
||||
font-family: "trebuchet ms", verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
} */
|
||||
/* :root {
|
||||
--mermaid-font-family: '"trebuchet ms", verdana, arial';
|
||||
--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive;
|
||||
--mermaid-font-family: '"Lucida Console", Monaco, monospace';
|
||||
} */
|
||||
svg {
|
||||
border: 2px solid darkred;
|
||||
}
|
||||
.exClass2 > rect, .exClass {
|
||||
fill: greenyellow !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
// Notice startOnLoad=false
|
||||
// This prevents default handling in mermaid from render before the e2e logic is applied
|
||||
// mermaid.initialize({
|
||||
// startOnLoad: false,
|
||||
// useMaxWidth: true,
|
||||
// // "themeCSS": ":root { --mermaid-font-family: \"trebuchet ms\", verdana, arial;}",
|
||||
// // fontFamily: '\"trebuchet ms\", verdana, arial;'
|
||||
// // fontFamily: '"Comic Sans MS", "Comic Sans", cursive'
|
||||
// // fontFamily: '"Mansalva", cursive',
|
||||
// // fontFamily: '"Noto Sans SC", sans-serif'
|
||||
// fontFamily: '"Noto Sans SC", sans-serif'
|
||||
// });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<!-- <meta charset="iso-8859-15"/> -->
|
||||
<script src="/e2e.js"></script>
|
||||
<!-- <link href="https://fonts.googleapis.com/css?family=Mansalva&display=swap" rel="stylesheet" /> -->
|
||||
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
/* font-family: 'Mansalva', cursive;*/
|
||||
/* font-family: 'Mansalva', cursive; */
|
||||
/* font-family: 'arial'; */
|
||||
/* font-family: "trebuchet ms", verdana, arial; */
|
||||
}
|
||||
/* div {
|
||||
font-family: 'arial';
|
||||
} */
|
||||
/* .mermaid-main-font {
|
||||
font-family: "trebuchet ms", verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
} */
|
||||
/* :root {
|
||||
--mermaid-font-family: '"trebuchet ms", verdana, arial';
|
||||
--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive;
|
||||
--mermaid-font-family: '"Lucida Console", Monaco, monospace';
|
||||
} */
|
||||
svg {
|
||||
border: 2px solid darkred;
|
||||
}
|
||||
.exClass2 > rect, .exClass {
|
||||
fill: greenyellow !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
// Notice startOnLoad=false
|
||||
// This prevents default handling in mermaid from render before the e2e logic is applied
|
||||
// mermaid.initialize({
|
||||
// startOnLoad: false,
|
||||
// useMaxWidth: true,
|
||||
// // "themeCSS": ":root { --mermaid-font-family: \"trebuchet ms\", verdana, arial;}",
|
||||
// // fontFamily: '\"trebuchet ms\", verdana, arial;'
|
||||
// // fontFamily: '"Comic Sans MS", "Comic Sans", cursive'
|
||||
// // fontFamily: '"Mansalva", cursive',
|
||||
// // fontFamily: '"Noto Sans SC", sans-serif'
|
||||
// fontFamily: '"Noto Sans SC", sans-serif'
|
||||
// });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
6
cypress/platform/exploit.js
Normal file
6
cypress/platform/exploit.js
Normal file
@ -0,0 +1,6 @@
|
||||
const div = parent.document.createElement('div');
|
||||
div.id = 'the-malware';
|
||||
div.className = 'malware';
|
||||
div.innerHTML = 'XSS Succeeded';
|
||||
parent.document.getElementsByTagName('body')[0].appendChild(div);
|
||||
throw new Error('XSS Succeded');
|
@ -1,46 +1,46 @@
|
||||
<html>
|
||||
<head>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<style>body {
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="mermaid">
|
||||
graph TB
|
||||
subgraph One
|
||||
a1-->a2-->a3
|
||||
end
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
graph TB
|
||||
a_a --> b_b:::apa --> c_c:::apa
|
||||
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
|
||||
class a_a apa;
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
graph TB
|
||||
a_a(Aftonbladet) --> b_b[gorilla]:::apa --> c_c{chimp}:::apa -->a_a
|
||||
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"
|
||||
</div>
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
theme: 'forest',
|
||||
// themeCSS: '.node rect { fill: red; }',
|
||||
logLevel: 3,
|
||||
flowchart: { curve: 'linear' },
|
||||
gantt: { axisFormat: '%m/%d/%Y' },
|
||||
sequence: { actorMargin: 50 },
|
||||
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<html>
|
||||
<head>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<style>body {
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="mermaid">
|
||||
graph TB
|
||||
subgraph One
|
||||
a1-->a2-->a3
|
||||
end
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
graph TB
|
||||
a_a --> b_b:::apa --> c_c:::apa
|
||||
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
|
||||
class a_a apa;
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
graph TB
|
||||
a_a(Aftonbladet) --> b_b[gorilla]:::apa --> c_c{chimp}:::apa -->a_a
|
||||
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"
|
||||
</div>
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
theme: 'forest',
|
||||
// themeCSS: '.node rect { fill: red; }',
|
||||
logLevel: 3,
|
||||
flowchart: { curve: 'linear' },
|
||||
gantt: { axisFormat: '%m/%d/%Y' },
|
||||
sequence: { actorMargin: 50 },
|
||||
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user