diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 7e0c78ff1e..fa15f39e1c 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -3,9 +3,9 @@ contact_links:
- name: GitHub Discussions
url: https://github.com/mermaid-js/mermaid/discussions
about: Ask the Community questions or share your own graphs in our discussions.
- - name: Slack
- url: https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE
- about: Join our Community on Slack for Help and a casual chat.
+ - name: Discord
+ url: https://discord.gg/wwtabKgp8y
+ about: Join our Community on Discord for Help and a casual chat.
- name: Documentation
url: https://mermaid.js.org
about: Read our documentation for all that Mermaid.js can offer.
diff --git a/.github/lychee.toml b/.github/lychee.toml
index b13e536161..4af304a990 100644
--- a/.github/lychee.toml
+++ b/.github/lychee.toml
@@ -34,8 +34,8 @@ exclude = [
# Don't check files that are generated during the build via `pnpm docs:code`
'packages/mermaid/src/docs/config/setup/*',
-# Ignore slack invite
-"https://join.slack.com/"
+# Ignore Discord invite
+"https://discord.gg"
]
# Exclude all private IPs from checking.
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index ff34d24fd0..f20204a714 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -14,5 +14,5 @@ Make sure you
- [ ] :book: have read the [contribution guidelines](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md)
- [ ] :computer: have added necessary unit/e2e tests.
-- [ ] :notebook: have added documentation. Make sure [`MERMAID_RELEASE_VERSION`](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/docs/community/development.md#3-update-documentation) is used for all new features.
+- [ ] :notebook: have added documentation. Make sure [`MERMAID_RELEASE_VERSION`](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/docs/community/contributing.md#update-documentation) is used for all new features.
- [ ] :bookmark: targeted `develop` branch
diff --git a/.github/workflows/e2e-applitools.yml b/.github/workflows/e2e-applitools.yml
index 543fb5dbb4..fd32e59adf 100644
--- a/.github/workflows/e2e-applitools.yml
+++ b/.github/workflows/e2e-applitools.yml
@@ -28,7 +28,7 @@ jobs:
- if: ${{ ! env.USE_APPLI }}
name: Warn if not using Applitools
run: |
- echo "::error,title=Not using Applitols::APPLITOOLS_API_KEY is empty, disabling Applitools for this run."
+ echo "::error,title=Not using Applitools::APPLITOOLS_API_KEY is empty, disabling Applitools for this run."
- uses: actions/checkout@v4
diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index 71806a9c46..b8232b8c0e 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -1,16 +1,62 @@
+# We use github cache to save snapshots between runs.
+# For PRs and MergeQueues, the target commit is used, and for push events, github.event.previous is used.
+# If a snapshot for a given Hash is not found, we checkout that commit, run the tests and cache the snapshots.
+# These are then downloaded before running the E2E, providing the reference snapshots.
+# If there are any errors, the diff image is uploaded to artifacts, and the user is notified.
+
name: E2E
on:
push:
+ branches-ignore:
+ - 'gh-readonly-queue/**'
pull_request:
merge_group:
permissions:
contents: read
+env:
+ # For PRs and MergeQueues, the target commit is used, and for push events, github.event.previous is used.
+ targetHash: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || (github.event.before == '0000000000000000000000000000000000000000' && 'develop' || github.event.before) }}
+
jobs:
+ cache:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v2
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 18.x
+ - name: Cache snapshots
+ id: cache-snapshot
+ uses: actions/cache@v4
+ with:
+ save-always: true
+ path: ./cypress/snapshots
+ key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
+
+ # If a snapshot for a given Hash is not found, we checkout that commit, run the tests and cache the snapshots.
+ - name: Switch to base branch
+ if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ env.targetHash }}
+
+ - name: Cypress run
+ uses: cypress-io/github-action@v4
+ id: cypress-snapshot-gen
+ if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
+ with:
+ start: pnpm run dev
+ wait-on: 'http://localhost:9000'
+ browser: chrome
+
e2e:
runs-on: ubuntu-latest
+ needs: cache
strategy:
fail-fast: false
matrix:
@@ -27,6 +73,14 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
+ # These cached snapshots are downloaded, providing the reference snapshots.
+ - name: Cache snapshots
+ id: cache-snapshot
+ uses: actions/cache/restore@v3
+ with:
+ path: ./cypress/snapshots
+ key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
+
# Install NPM dependencies, cache them correctly
# and run all Cypress tests
- name: Cypress run
@@ -38,6 +92,7 @@ jobs:
with:
start: pnpm run dev:coverage
wait-on: 'http://localhost:9000'
+ browser: chrome
# Disable recording if we don't have an API key
# e.g. if this action was run from a fork
record: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
@@ -46,6 +101,7 @@ jobs:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
VITEST_COVERAGE: true
CYPRESS_COMMIT: ${{ github.sha }}
+
- name: Upload Coverage to Codecov
uses: codecov/codecov-action@v3
# Run step only pushes to develop and pull_requests
@@ -57,9 +113,55 @@ jobs:
fail_ci_if_error: false
verbose: true
token: 6845cc80-77ee-4e17-85a1-026cd95e0766
+
+ # We upload the artifacts into numbered archives to prevent overwriting
- name: Upload Artifacts
- uses: actions/upload-artifact@v3
- if: ${{ failure() && steps.cypress.conclusion == 'failure' }}
+ uses: actions/upload-artifact@v4
+ if: ${{ always() }}
+ with:
+ name: snapshots-${{ matrix.containers }}
+ retention-days: 1
+ path: ./cypress/snapshots
+
+ combineArtifacts:
+ needs: e2e
+ runs-on: ubuntu-latest
+ if: ${{ always() }}
+ steps:
+ # Download all snapshot artifacts and merge them into a single folder
+ - name: Download All Artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: snapshots
+ pattern: snapshots-*
+ merge-multiple: true
+
+ # For successful push events, we save the snapshots cache
+ - name: Save snapshots cache
+ id: cache-upload
+ if: ${{ github.event_name == 'push' && needs.e2e.result != 'failure' }}
+ uses: actions/cache/save@v3
+ with:
+ path: ./snapshots
+ key: ${{ runner.os }}-snapshots-${{ github.event.after }}
+
+ - name: Flatten images to a folder
+ if: ${{ needs.e2e.result == 'failure' }}
+ run: |
+ mkdir errors
+ cd snapshots
+ find . -mindepth 2 -type d -name "*__diff_output__*" -exec sh -c 'mv "$0"/*.png ../errors/' {} \;
+
+ - name: Upload Error snapshots
+ if: ${{ needs.e2e.result == 'failure' }}
+ uses: actions/upload-artifact@v4
+ id: upload-artifacts
with:
name: error-snapshots
- path: cypress/snapshots/**/__diff_output__/*
+ retention-days: 10
+ path: errors/
+
+ - name: Notify Users
+ if: ${{ needs.e2e.result == 'failure' }}
+ run: |
+ echo "::error title=Visual tests failed::You can view images that failed by downloading the error-snapshots artifact: ${{ steps.upload-artifacts.outputs.artifact-url }}"
diff --git a/.github/workflows/link-checker.yml b/.github/workflows/link-checker.yml
index c3e2ee44fe..3d4956945e 100644
--- a/.github/workflows/link-checker.yml
+++ b/.github/workflows/link-checker.yml
@@ -36,7 +36,7 @@ jobs:
restore-keys: cache-lychee-
- name: Link Checker
- uses: lycheeverse/lychee-action@v1.8.0
+ uses: lycheeverse/lychee-action@v1.9.1
with:
args: >-
--config .github/lychee.toml
diff --git a/.github/workflows/release-draft.yml b/.github/workflows/release-draft.yml
index 8ad1b13ecd..db1dd1f485 100644
--- a/.github/workflows/release-draft.yml
+++ b/.github/workflows/release-draft.yml
@@ -3,7 +3,7 @@ name: Draft Release
on:
push:
branches:
- - develop
+ - master
permissions:
contents: read
diff --git a/.github/workflows/update-browserlist.yml b/.github/workflows/update-browserlist.yml
index 0a83df795d..f4fa2a982f 100644
--- a/.github/workflows/update-browserlist.yml
+++ b/.github/workflows/update-browserlist.yml
@@ -9,10 +9,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - run: npx browserslist@latest --update-db
+ - uses: pnpm/action-setup@v2
+ - run: npx update-browserslist-db@latest
- name: Commit changes
uses: EndBug/add-and-commit@v9
with:
author_name: ${{ github.actor }}
author_email: ${{ github.actor }}@users.noreply.github.com
message: 'chore: update browsers list'
+ push: false
+ - name: Create Pull Request
+ uses: peter-evans/create-pull-request@v5
+ with:
+ branch: update-browserslist
+ title: Update Browserslist
diff --git a/.gitignore b/.gitignore
index 6a1cc85e51..e6728b03f7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,3 +46,4 @@ stats/
demos/dev/**
!/demos/dev/example.html
+tsx-0/**
diff --git a/.npmrc b/.npmrc
index 4c2f52b3be..e72930ead1 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1,2 +1,3 @@
+registry=https://registry.npmjs.org
auto-install-peers=true
strict-peer-dependencies=false
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index 3142c57605..0000000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,78 +0,0 @@
-# Contributing
-
-Please read in detail about how to contribute documentation and code on the [Mermaid documentation site.](https://mermaid-js.github.io/mermaid/#/development)
-
----
-
-# Mermaid contribution cheat-sheet
-
-## Requirements
-
-- [volta](https://volta.sh/) to manage node versions.
-- [Node.js](https://nodejs.org/en/). `volta install node`
-- [pnpm](https://pnpm.io/) package manager. `volta install pnpm`
-
-## Development Installation
-
-If you don't have direct access to push to mermaid repositories, make a fork first. Then clone. Or clone directly from mermaid-js:
-
-```bash
-git clone git@github.com:mermaid-js/mermaid.git
-cd mermaid
-```
-
-Install required packages:
-
-```bash
-# npx is required for first install as volta support for pnpm is not added yet.
-npx pnpm install
-pnpm test # run unit tests
-pnpm dev # starts a dev server
-```
-
-Open
- 📖 Documentation | 🚀 Getting Started | 🌐 CDN | 🙌 Join Us + 📖 Documentation | 🚀 Getting Started | 🌐 CDN | 🙌 Join Us
简体中文
@@ -33,7 +33,7 @@ Try Live Editor previews of future releases:
@@ -74,12 +74,12 @@ Mermaid addresses this problem by enabling users to create easily modifiable dia
Mermaid allows even non-programmers to easily create detailed diagrams through the [Mermaid Live Editor](https://mermaid.live/).
-For video tutorials, visit our [Tutorials](./docs/config/Tutorials.md) page.
+For video tutorials, visit our [Tutorials](./docs/ecosystem/tutorials.md) page.
Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations-community.md).
You can also use Mermaid within [GitHub](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) as well many of your other favorite applications—check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations-community.md).
-For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/intro/getting-started.md), [Usage](./docs/config/usage.md) and [Tutorials](./docs/config/Tutorials.md).
+For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/intro/getting-started.md), [Usage](./docs/config/usage.md) and [Tutorials](./docs/ecosystem/tutorials.md).
In our release process we rely heavily on visual regression tests using [applitools](https://applitools.com/). Applitools is a great service which has been easy to use and integrate with our tests.
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 98975ea331..c468b2d9fa 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -15,7 +15,7 @@ Mermaid
实时编辑器!
- 📖 文档 | 🚀 入门 | 🌐 CDN | 🙌 加入我们 + 📖 文档 | 🚀 入门 | 🌐 CDN | 🙌 加入我们
English
@@ -34,7 +34,7 @@ Mermaid
[![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
[![NPM Downloads](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid)
-[![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)
+[![Join our Discord!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=discord&label=discord)](https://discord.gg/wwtabKgp8y)
[![Twitter Follow](https://img.shields.io/badge/Social-mermaidjs__-blue?style=social&logo=X)](https://twitter.com/mermaidjs_)
@@ -57,9 +57,9 @@ Mermaid 是一个基于 Javascript 的图表绘制工具,通过解析类 Markd
Mermaid 通过允许用户创建便于修改的图表来解决这一难题,它也可以作为生产脚本(或其他代码)的一部分。
Mermaid 甚至能让非程序员也能通过 [Mermaid Live Editor](https://mermaid.live/) 轻松创建详细的图表。
-你可以访问 [教程](./docs/config/Tutorials.md) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](./docs/ecosystem/integrations-community.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。
+你可以访问 [教程](./docs/ecosystem/tutorials.md) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](./docs/ecosystem/integrations-community.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。
-如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/intro/getting-started.md), [用法](./docs/config/usage.md) 和 [教程](./docs/config/Tutorials.md).
+如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/intro/getting-started.md), [用法](./docs/config/usage.md) 和 [教程](./docs/ecosystem/tutorials.md).
diff --git a/applitools.config.js b/applitools.config.js
deleted file mode 100644
index 4cf02220ac..0000000000
--- a/applitools.config.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// eslint-disable-next-line @typescript-eslint/no-var-requires
-const { defineConfig } = require('cypress');
-
-module.exports = defineConfig({
- testConcurrency: 1,
- browser: [
- // Add browsers with different viewports
- // { width: 800, height: 600, name: 'chrome' },
- // { width: 700, height: 500, name: 'firefox' },
- // { width: 1600, height: 1200, name: 'ie11' },
- // { width: 1024, height: 768, name: 'edgechromium' },
- // { width: 800, height: 600, name: 'safari' },
- // // Add mobile emulation devices in Portrait mode
- // { deviceName: 'iPhone X', screenOrientation: 'portrait' },
- // { deviceName: 'Pixel 2', screenOrientation: 'portrait' },
- ],
- // set batch name to the configuration
- // batchName: `Mermaid ${process.env.APPLI_BRANCH ?? "'no APPLI_BRANCH set'"}`,
-});
diff --git a/cSpell.json b/cSpell.json
index 76f395915f..4b8772347e 100644
--- a/cSpell.json
+++ b/cSpell.json
@@ -26,6 +26,7 @@
"città",
"classdef",
"codedoc",
+ "codemia",
"colour",
"commitlint",
"cpettitt",
@@ -101,6 +102,7 @@
"pathe",
"pbrolin",
"phpbb",
+ "pixelmatch",
"plantuml",
"playfair",
"pnpm",
@@ -123,6 +125,7 @@
"sidharth",
"sidharthv",
"sphinxcontrib",
+ "ssim",
"startx",
"starty",
"statediagram",
diff --git a/cypress.config.cjs b/cypress.config.cjs
deleted file mode 100644
index 30076c56ef..0000000000
--- a/cypress.config.cjs
+++ /dev/null
@@ -1,24 +0,0 @@
-/* eslint-disable @typescript-eslint/no-var-requires */
-
-const { defineConfig } = require('cypress');
-const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
-const coverage = require('@cypress/code-coverage/task');
-
-module.exports = defineConfig({
- projectId: 'n2sma2',
- e2e: {
- specPattern: 'cypress/integration/**/*.{js,jsx,ts,tsx}',
- setupNodeEvents(on, config) {
- coverage(on, config);
- addMatchImageSnapshotPlugin(on, config);
- // copy any needed variables from process.env to config.env
- config.env.useAppli = process.env.USE_APPLI ? true : false;
-
- // do not forget to return the changed config object!
- return config;
- },
- },
- video: false,
-});
-
-require('@applitools/eyes-cypress')(module);
diff --git a/cypress.config.ts b/cypress.config.ts
new file mode 100644
index 0000000000..4182d92a87
--- /dev/null
+++ b/cypress.config.ts
@@ -0,0 +1,30 @@
+import { defineConfig } from 'cypress';
+import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';
+import coverage from '@cypress/code-coverage/task';
+import eyesPlugin from '@applitools/eyes-cypress';
+export default eyesPlugin(
+ defineConfig({
+ projectId: 'n2sma2',
+ viewportWidth: 1440,
+ viewportHeight: 1024,
+ e2e: {
+ specPattern: 'cypress/integration/**/*.{js,ts}',
+ setupNodeEvents(on, config) {
+ coverage(on, config);
+ on('before:browser:launch', (browser, launchOptions) => {
+ if (browser.name === 'chrome' && browser.isHeadless) {
+ launchOptions.args.push('--window-size=1440,1024', '--force-device-scale-factor=1');
+ }
+ return launchOptions;
+ });
+ addMatchImageSnapshotPlugin(on, config);
+ // copy any needed variables from process.env to config.env
+ config.env.useAppli = process.env.USE_APPLI ? true : false;
+
+ // do not forget to return the changed config object!
+ return config;
+ },
+ },
+ video: false,
+ })
+);
diff --git a/cypress/helpers/util.ts b/cypress/helpers/util.ts
index c656f638da..aed5d7973c 100644
--- a/cypress/helpers/util.ts
+++ b/cypress/helpers/util.ts
@@ -10,7 +10,7 @@ interface CypressConfig {
type CypressMermaidConfig = MermaidConfig & CypressConfig;
interface CodeObject {
- code: string;
+ code: string | string[];
mermaid: CypressMermaidConfig;
}
@@ -25,7 +25,7 @@ const batchId: string =
: Cypress.env('CYPRESS_COMMIT') || Date.now().toString());
export const mermaidUrl = (
- graphStr: string,
+ graphStr: string | string[],
options: CypressMermaidConfig,
api: boolean
): string => {
@@ -82,7 +82,7 @@ export const urlSnapshotTest = (
};
export const renderGraph = (
- graphStr: string,
+ graphStr: string | string[],
options: CypressMermaidConfig = {},
api = false
): void => {
diff --git a/cypress/integration/other/configuration.spec.js b/cypress/integration/other/configuration.spec.js
index 7cbc5d1059..23338271f5 100644
--- a/cypress/integration/other/configuration.spec.js
+++ b/cypress/integration/other/configuration.spec.js
@@ -117,7 +117,6 @@ describe('Configuration', () => {
});
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');
diff --git a/cypress/integration/other/rerender.spec.js b/cypress/integration/other/rerender.spec.js
index f160a2e273..d14c6257e0 100644
--- a/cypress/integration/other/rerender.spec.js
+++ b/cypress/integration/other/rerender.spec.js
@@ -1,14 +1,12 @@
describe('Rerendering', () => {
it('should be able to render after an error has occurred', () => {
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');
diff --git a/cypress/integration/rendering/classDiagram-v2.spec.js b/cypress/integration/rendering/classDiagram-v2.spec.js
index 37e9cada02..20a1aea0ab 100644
--- a/cypress/integration/rendering/classDiagram-v2.spec.js
+++ b/cypress/integration/rendering/classDiagram-v2.spec.js
@@ -571,4 +571,14 @@ class C13["With Città foreign language"]
{ logLevel: 1, flowchart: { htmlLabels: false } }
);
});
+ it('should render a simple class diagram with style definition', () => {
+ imgSnapshotTest(
+ `
+ classDiagram-v2
+ class Class10
+ style Class10 fill:#f9f,stroke:#333,stroke-width:4px
+ `,
+ { logLevel: 1, flowchart: { htmlLabels: false } }
+ );
+ });
});
diff --git a/cypress/integration/rendering/debug.spec.js b/cypress/integration/rendering/debug.spec.js
deleted file mode 100644
index 56ad0f15f8..0000000000
--- a/cypress/integration/rendering/debug.spec.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { imgSnapshotTest } from '../../helpers/util.ts';
-
-describe('Flowchart', () => {
- it('34: testing the label width in percy', () => {
- imgSnapshotTest(
- `graph TD
- A[Christmas]
- `,
- { theme: 'forest', fontFamily: '"Noto Sans SC", sans-serif' }
- );
- });
-});
diff --git a/cypress/integration/rendering/flowchart-v2.spec.js b/cypress/integration/rendering/flowchart-v2.spec.js
index e23820ffa3..857d395be7 100644
--- a/cypress/integration/rendering/flowchart-v2.spec.js
+++ b/cypress/integration/rendering/flowchart-v2.spec.js
@@ -741,6 +741,25 @@ A ~~~ B
);
});
+ it('5059: Should render when subgraph contains only subgraphs, has link to outside and itself is part of a link', () => {
+ imgSnapshotTest(
+ `flowchart
+
+ subgraph Main
+ subgraph Child1
+ Node1
+ Node2
+ end
+ subgraph Child2
+ Node3
+ Node4
+ end
+ end
+ Main --> Out1
+ Child2 --> Out2`
+ );
+ });
+
describe('Markdown strings flowchart (#4220)', () => {
describe('html labels', () => {
it('With styling and classes', () => {
diff --git a/cypress/integration/rendering/gantt.spec.js b/cypress/integration/rendering/gantt.spec.js
index 998a092c24..4abde9d446 100644
--- a/cypress/integration/rendering/gantt.spec.js
+++ b/cypress/integration/rendering/gantt.spec.js
@@ -245,7 +245,10 @@ describe('Gantt diagram', () => {
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);
+ expect(maxWidthValue).to.be.within(
+ Cypress.config().viewportWidth * 0.95,
+ Cypress.config().viewportWidth * 1.05
+ );
});
});
@@ -285,11 +288,11 @@ 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 * 0.95, 484 * 1.05);
- expect(width).to.be.within(984 * 0.95, 984 * 1.05);
+ expect(width).to.be.within(
+ Cypress.config().viewportWidth * 0.95,
+ Cypress.config().viewportWidth * 1.05
+ );
expect(svg).to.not.have.attr('style');
});
});
@@ -580,4 +583,106 @@ describe('Gantt diagram', () => {
{}
);
});
+
+ it("should render when there's a semicolon in the title", () => {
+ imgSnapshotTest(
+ `
+ gantt
+ title ;Gantt With a Semicolon in the Title
+ dateFormat YYYY-MM-DD
+ section Section
+ A task :a1, 2014-01-01, 30d
+ Another task :after a1 , 20d
+ section Another
+ Task in sec :2014-01-12 , 12d
+ another task : 24d
+ `,
+ {}
+ );
+ });
+
+ it("should render when there's a semicolon in a section is true", () => {
+ imgSnapshotTest(
+ `
+ gantt
+ title Gantt Digram
+ dateFormat YYYY-MM-DD
+ section ;Section With a Semicolon
+ A task :a1, 2014-01-01, 30d
+ Another task :after a1 , 20d
+ section Another
+ Task in sec :2014-01-12 , 12d
+ another task : 24d
+ `,
+ {}
+ );
+ });
+
+ it("should render when there's a semicolon in the task data", () => {
+ imgSnapshotTest(
+ `
+ gantt
+ title Gantt Digram
+ dateFormat YYYY-MM-DD
+ section Section
+ ;A task with a semiclon :a1, 2014-01-01, 30d
+ Another task :after a1 , 20d
+ section Another
+ Task in sec :2014-01-12 , 12d
+ another task : 24d
+ `,
+ {}
+ );
+ });
+
+ it("should render when there's a hashtag in the title", () => {
+ imgSnapshotTest(
+ `
+ gantt
+ title #Gantt With a Hashtag in the Title
+ dateFormat YYYY-MM-DD
+ section Section
+ A task :a1, 2014-01-01, 30d
+ Another task :after a1 , 20d
+ section Another
+ Task in sec :2014-01-12 , 12d
+ another task : 24d
+ `,
+ {}
+ );
+ });
+
+ it("should render when there's a hashtag in a section is true", () => {
+ imgSnapshotTest(
+ `
+ gantt
+ title Gantt Digram
+ dateFormat YYYY-MM-DD
+ section #Section With a Hashtag
+ A task :a1, 2014-01-01, 30d
+ Another task :after a1 , 20d
+ section Another
+ Task in sec :2014-01-12 , 12d
+ another task : 24d
+ `,
+ {}
+ );
+ });
+
+ it("should render when there's a hashtag in the task data", () => {
+ imgSnapshotTest(
+ `
+ gantt
+ title Gantt Digram
+ dateFormat YYYY-MM-DD
+ section Section
+ #A task with a hashtag :a1, 2014-01-01, 30d
+ Another task :after a1 , 20d
+ section Another
+ Task in sec :2014-01-12 , 12d
+ another task : 24d
+ `,
+ {}
+ );
+ });
});
diff --git a/cypress/integration/rendering/gitGraph.spec.js b/cypress/integration/rendering/gitGraph.spec.js
index d3e4dd9dde..19ddde31d4 100644
--- a/cypress/integration/rendering/gitGraph.spec.js
+++ b/cypress/integration/rendering/gitGraph.spec.js
@@ -826,4 +826,121 @@ gitGraph TB:
cherry-pick id: "M" parent:"B"`
);
});
+ it('41: should render default GitGraph with parallelCommits set to false', () => {
+ imgSnapshotTest(
+ `gitGraph
+ commit id:"1-abcdefg"
+ commit id:"2-abcdefg"
+ branch develop
+ commit id:"3-abcdefg"
+ commit id:"4-abcdefg"
+ checkout main
+ branch feature
+ commit id:"5-abcdefg"
+ commit id:"6-abcdefg"
+ checkout main
+ commit id:"7-abcdefg"
+ commit id:"8-abcdefg"
+ `,
+ { gitGraph: { parallelCommits: false } }
+ );
+ });
+ it('42: should render GitGraph with parallel commits', () => {
+ imgSnapshotTest(
+ `gitGraph
+ commit id:"1-abcdefg"
+ commit id:"2-abcdefg"
+ branch develop
+ commit id:"3-abcdefg"
+ commit id:"4-abcdefg"
+ checkout main
+ branch feature
+ commit id:"5-abcdefg"
+ commit id:"6-abcdefg"
+ checkout main
+ commit id:"7-abcdefg"
+ commit id:"8-abcdefg"
+ `,
+ { gitGraph: { parallelCommits: true } }
+ );
+ });
+ it('43: should render GitGraph with parallel commits | Vertical Branch', () => {
+ imgSnapshotTest(
+ `gitGraph TB:
+ commit id:"1-abcdefg"
+ commit id:"2-abcdefg"
+ branch develop
+ commit id:"3-abcdefg"
+ commit id:"4-abcdefg"
+ checkout main
+ branch feature
+ commit id:"5-abcdefg"
+ commit id:"6-abcdefg"
+ checkout main
+ commit id:"7-abcdefg"
+ commit id:"8-abcdefg"
+ `,
+ { gitGraph: { parallelCommits: true } }
+ );
+ });
+ it('44: should render GitGraph with unconnected branches and no parallel commits', () => {
+ imgSnapshotTest(
+ `gitGraph
+ branch dev
+ branch v2
+ branch feat
+ commit id:"1-abcdefg"
+ commit id:"2-abcdefg"
+ checkout main
+ commit id:"3-abcdefg"
+ checkout dev
+ commit id:"4-abcdefg"
+ checkout v2
+ commit id:"5-abcdefg"
+ checkout main
+ commit id:"6-abcdefg"
+ `,
+ { gitGraph: { parallelCommits: false } }
+ );
+ });
+ it('45: should render GitGraph with unconnected branches and parallel commits', () => {
+ imgSnapshotTest(
+ `gitGraph
+ branch dev
+ branch v2
+ branch feat
+ commit id:"1-abcdefg"
+ commit id:"2-abcdefg"
+ checkout main
+ commit id:"3-abcdefg"
+ checkout dev
+ commit id:"4-abcdefg"
+ checkout v2
+ commit id:"5-abcdefg"
+ checkout main
+ commit id:"6-abcdefg"
+ `,
+ { gitGraph: { parallelCommits: true } }
+ );
+ });
+ it('46: should render GitGraph with unconnected branches and parallel commits | Vertical Branch', () => {
+ imgSnapshotTest(
+ `gitGraph TB:
+ branch dev
+ branch v2
+ branch feat
+ commit id:"1-abcdefg"
+ commit id:"2-abcdefg"
+ checkout main
+ commit id:"3-abcdefg"
+ checkout dev
+ commit id:"4-abcdefg"
+ checkout v2
+ commit id:"5-abcdefg"
+ checkout main
+ commit id:"6-abcdefg"
+ `,
+ { gitGraph: { parallelCommits: true } }
+ );
+ });
});
diff --git a/cypress/integration/rendering/sequencediagram.spec.js b/cypress/integration/rendering/sequencediagram.spec.js
index 7659138241..10432f057f 100644
--- a/cypress/integration/rendering/sequencediagram.spec.js
+++ b/cypress/integration/rendering/sequencediagram.spec.js
@@ -792,6 +792,34 @@ context('Sequence diagram', () => {
});
});
context('links', () => {
+ it('should support actor links', () => {
+ renderGraph(
+ `
+ sequenceDiagram
+ link Alice: Dashboard @ https://dashboard.contoso.com/alice
+ link Alice: Wiki @ https://wiki.contoso.com/alice
+ link John: Dashboard @ https://dashboard.contoso.com/john
+ link John: Wiki @ https://wiki.contoso.com/john
+ Alice->>John: Hello John
+ John-->>Alice: Great
day!
+ `,
+ { securityLevel: 'loose' }
+ );
+ cy.get('#actor0_popup').should((popupMenu) => {
+ const style = popupMenu.attr('style');
+ expect(style).to.undefined;
+ });
+ cy.get('#root-0').click();
+ cy.get('#actor0_popup').should((popupMenu) => {
+ const style = popupMenu.attr('style');
+ expect(style).to.match(/^display: block;$/);
+ });
+ cy.get('#root-0').click();
+ cy.get('#actor0_popup').should((popupMenu) => {
+ const style = popupMenu.attr('style');
+ expect(style).to.match(/^display: none;$/);
+ });
+ });
it('should support actor links and properties EXPERIMENTAL: USE WITH CAUTION', () => {
//Be aware that the syntax for "properties" is likely to be changed.
imgSnapshotTest(
@@ -930,4 +958,36 @@ context('Sequence diagram', () => {
});
});
});
+ context('render after error', () => {
+ it('should render diagram after fixing destroy participant error', () => {
+ cy.on('uncaught:exception', (err) => {
+ return false;
+ });
+
+ renderGraph([
+ `sequenceDiagram
+ Alice->>Bob: Hello Bob, how are you ?
+ Bob->>Alice: Fine, thank you. And you?
+ create participant Carl
+ Alice->>Carl: Hi Carl!
+ create actor D as Donald
+ Carl->>D: Hi!
+ destroy Carl
+ Alice-xCarl: We are too many
+ destroy Bo
+ Bob->>Alice: I agree`,
+ `sequenceDiagram
+ Alice->>Bob: Hello Bob, how are you ?
+ Bob->>Alice: Fine, thank you. And you?
+ create participant Carl
+ Alice->>Carl: Hi Carl!
+ create actor D as Donald
+ Carl->>D: Hi!
+ destroy Carl
+ Alice-xCarl: We are too many
+ destroy Bob
+ Bob->>Alice: I agree`,
+ ]);
+ });
+ });
});
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index 3589640d98..6fc1fe17db 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -24,8 +24,18 @@
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
-// import '@percy/cypress';
-
import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command';
+// The SSIM comparison method can be used if the pixelmatch is throwing lots of false positives.
+// SSIM actually does not catch minute changes in the image, so it is not as accurate as pixelmatch.
+// addMatchImageSnapshotCommand({
+// comparisonMethod: 'ssim',
+// failureThreshold: 0.01,
+// failureThresholdType: 'percent',
+// customDiffConfig: {
+// ssim: 'fast',
+// },
+// blur: 1,
+// });
+
addMatchImageSnapshotCommand();
diff --git a/demos/gantt.html b/demos/gantt.html
index 88f52ef5c9..9c82371abe 100644
--- a/demos/gantt.html
+++ b/demos/gantt.html
@@ -30,6 +30,21 @@
+ gantt + title #; Gantt Diagrams Allow Semicolons and Hashtags #;! + accTitle: A simple sample gantt diagram + accDescr: 2 sections with 2 tasks each, from 2014 + dateFormat YYYY-MM-DD + section #;Section + #;A task :a1, 2014-01-01, 30d + #;Another task :after a1 , 20d + section #;Another + Task in sec :2014-01-12 , 12d + another task : 24d ++
gantt title Airworks roadmap diff --git a/demos/sequence.html b/demos/sequence.html index 3345fed17a..8eecae6105 100644 --- a/demos/sequence.html +++ b/demos/sequence.html @@ -23,6 +23,10 @@Sequence diagram demos
participant Alice participant Bob participant John as John
Second Line + link Alice: Dashboard @ https://dashboard.contoso.com/alice + link Alice: Wiki @ https://wiki.contoso.com/alice + link John: Dashboard @ https://dashboard.contoso.com/john + link John: Wiki @ https://wiki.contoso.com/john autonumber 10 10 rect rgb(200, 220, 100) rect rgb(200, 255, 200) @@ -62,6 +66,26 @@Sequence diagram demos
+ --- + title: With forced menus + config: + sequence: + forceMenus: true + --- + sequenceDiagram + participant Alice + participant John + link Alice: Dashboard @ https://dashboard.contoso.com/alice + link Alice: Wiki @ https://wiki.contoso.com/alice + link John: Dashboard @ https://dashboard.contoso.com/john + link John: Wiki @ https://wiki.contoso.com/john + Alice->>John: Hello John, how are you? + John-->>Alice: Great! + Alice-)John: See you later! ++
sequenceDiagram accTitle: Sequence diagram title is here accDescr: Hello friends @@ -164,13 +188,6 @@-Sequence diagram demos
end
- sequenceDiagram - actor Alice - actor John - Alice-xJohn: Hello John, how are you? - John--xAlice: Great! -