diff --git a/.build/common.ts b/.build/common.ts index e2190974f..86ccd15d1 100644 --- a/.build/common.ts +++ b/.build/common.ts @@ -1,3 +1,9 @@ +export interface PackageOptions { + name: string; + packageName: string; + file: string; +} + /** * Shared common options for both ESBuild and Vite */ @@ -27,4 +33,4 @@ export const packageOptions = { packageName: 'mermaid-layout-elk', file: 'layouts.ts', }, -} as const; +} as const satisfies Record; diff --git a/.changeset/chilly-hotels-mix.md b/.changeset/chilly-hotels-mix.md new file mode 100644 index 000000000..642ab6ecf --- /dev/null +++ b/.changeset/chilly-hotels-mix.md @@ -0,0 +1,5 @@ +--- +'mermaid': patch +--- + +fix: Jagged edge fix for icon shape diff --git a/.changeset/dry-plums-glow.md b/.changeset/dry-plums-glow.md deleted file mode 100644 index e5b95dc3c..000000000 --- a/.changeset/dry-plums-glow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'mermaid': patch ---- - -Fix for issue with calculation of label width when using in firefox diff --git a/.changeset/dry-students-act.md b/.changeset/dry-students-act.md new file mode 100644 index 000000000..43f439f2e --- /dev/null +++ b/.changeset/dry-students-act.md @@ -0,0 +1,5 @@ +--- +'mermaid': patch +--- + +Add missing TypeScript dependencies diff --git a/.changeset/heavy-cats-mate.md b/.changeset/heavy-cats-mate.md new file mode 100644 index 000000000..c903cc47e --- /dev/null +++ b/.changeset/heavy-cats-mate.md @@ -0,0 +1,5 @@ +--- +'mermaid': patch +--- + +fix: Icon color fix for colored icons. diff --git a/.cspell/code-terms.txt b/.cspell/code-terms.txt index 8e4c02261..f4862006f 100644 --- a/.cspell/code-terms.txt +++ b/.cspell/code-terms.txt @@ -26,6 +26,7 @@ concat controlx controly CSSCLASS +curv CYLINDEREND CYLINDERSTART DAGA diff --git a/.cspell/cspell.config.yaml b/.cspell/cspell.config.yaml index 33d690193..b16040c8c 100644 --- a/.cspell/cspell.config.yaml +++ b/.cspell/cspell.config.yaml @@ -28,6 +28,9 @@ dictionaryDefinitions: - name: suggestions words: - none + - disp + - subproc + - tria suggestWords: - seperator:separator - vertice:vertex diff --git a/.cspell/mermaid-terms.txt b/.cspell/mermaid-terms.txt index 59a3d108f..8551bd196 100644 --- a/.cspell/mermaid-terms.txt +++ b/.cspell/mermaid-terms.txt @@ -5,6 +5,7 @@ bmatrix braintree catmull compositTitleSize +curv doublecircle elems gantt @@ -24,6 +25,7 @@ multigraph nodesep NOTEGROUP Pinterest +procs rankdir ranksep rect diff --git a/.esbuild/build.ts b/.esbuild/build.ts index 2bb42a557..423e8f047 100644 --- a/.esbuild/build.ts +++ b/.esbuild/build.ts @@ -8,7 +8,10 @@ import { defaultOptions, getBuildConfig } from './util.js'; const shouldVisualize = process.argv.includes('--visualize'); const buildPackage = async (entryName: keyof typeof packageOptions) => { - const commonOptions: MermaidBuildOptions = { ...defaultOptions, entryName } as const; + const commonOptions: MermaidBuildOptions = { + ...defaultOptions, + options: packageOptions[entryName], + } as const; const buildConfigs: MermaidBuildOptions[] = [ // package.mjs { ...commonOptions }, @@ -40,7 +43,7 @@ const buildPackage = async (entryName: keyof typeof packageOptions) => { continue; } const fileName = Object.keys(metafile.outputs) - .find((file) => !file.includes('chunks') && file.endsWith('js')) + .find((file) => !file.includes('chunks') && file.endsWith('js'))! .replace('dist/', ''); // Upload metafile into https://esbuild.github.io/analyze/ await writeFile(`stats/${fileName}.meta.json`, JSON.stringify(metafile)); diff --git a/.esbuild/server.ts b/.esbuild/server.ts index ef61ebec2..6e1bcb460 100644 --- a/.esbuild/server.ts +++ b/.esbuild/server.ts @@ -9,13 +9,18 @@ import { generateLangium } from '../.build/generateLangium.js'; import { defaultOptions, getBuildConfig } from './util.js'; const configs = Object.values(packageOptions).map(({ packageName }) => - getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: packageName }) + getBuildConfig({ + ...defaultOptions, + minify: false, + core: false, + options: packageOptions[packageName], + }) ); const mermaidIIFEConfig = getBuildConfig({ ...defaultOptions, minify: false, core: false, - entryName: 'mermaid', + options: packageOptions.mermaid, format: 'iife', }); configs.push(mermaidIIFEConfig); diff --git a/.esbuild/util.ts b/.esbuild/util.ts index 522176113..6d6d1d59b 100644 --- a/.esbuild/util.ts +++ b/.esbuild/util.ts @@ -3,7 +3,7 @@ import { fileURLToPath } from 'url'; import type { BuildOptions } from 'esbuild'; import { readFileSync } from 'fs'; import jsonSchemaPlugin from './jsonSchemaPlugin.js'; -import { packageOptions } from '../.build/common.js'; +import type { PackageOptions } from '../.build/common.js'; import { jisonPlugin } from './jisonPlugin.js'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); @@ -13,10 +13,10 @@ export interface MermaidBuildOptions extends BuildOptions { core: boolean; metafile: boolean; format: 'esm' | 'iife'; - entryName: keyof typeof packageOptions; + options: PackageOptions; } -export const defaultOptions: Omit = { +export const defaultOptions: Omit = { minify: false, metafile: false, core: false, @@ -52,9 +52,14 @@ const getFileName = (fileName: string, { core, format, minify }: MermaidBuildOpt }; export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => { - const { core, entryName, metafile, format, minify } = options; + const { + core, + metafile, + format, + minify, + options: { name, file, packageName }, + } = options; const external: string[] = ['require', 'fs', 'path']; - const { name, file, packageName } = packageOptions[entryName]; const outFileName = getFileName(name, options); const output: BuildOptions = buildOptions({ absWorkingDir: resolve(__dirname, `../packages/${packageName}`), diff --git a/.github/lychee.toml b/.github/lychee.toml index 2e3b08c41..288ab054a 100644 --- a/.github/lychee.toml +++ b/.github/lychee.toml @@ -44,7 +44,10 @@ exclude = [ "https://chromewebstore.google.com", # Drupal 403 -"https://(www.)?drupal.org" +"https://(www.)?drupal.org", + +# Swimm returns 404, eventhough the link is valid +"https://docs.swimm.io" ] # Exclude all private IPs from checking. diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index 6a43791ed..13b913c11 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -19,7 +19,7 @@ jobs: # uses version from "packageManager" field in package.json - name: Setup Node.js - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: cache: pnpm node-version-file: '.node-version' diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index eb0c4594a..79e9deea1 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -23,7 +23,7 @@ jobs: - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 - name: Setup Node.js - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: cache: pnpm node-version-file: '.node-version' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 65962ce64..94ede60ab 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -36,7 +36,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5 + uses: github/codeql-action/init@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 with: config-file: ./.github/codeql/codeql-config.yml languages: ${{ matrix.language }} @@ -48,7 +48,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5 + uses: github/codeql-action/autobuild@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -62,4 +62,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5 + uses: github/codeql-action/analyze@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 diff --git a/.github/workflows/e2e-applitools.yml b/.github/workflows/e2e-applitools.yml index 6da65afe5..b1eb70674 100644 --- a/.github/workflows/e2e-applitools.yml +++ b/.github/workflows/e2e-applitools.yml @@ -38,7 +38,7 @@ jobs: # uses version from "packageManager" field in package.json - name: Setup Node.js - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: node-version-file: '.node-version' diff --git a/.github/workflows/e2e-timings.yml b/.github/workflows/e2e-timings.yml new file mode 100644 index 000000000..e3f724d81 --- /dev/null +++ b/.github/workflows/e2e-timings.yml @@ -0,0 +1,53 @@ +name: E2E - Generate Timings + +on: + # run this workflow every night at 3am + schedule: + - cron: '28 3 * * *' + # or when the user triggers it from GitHub Actions page + workflow_dispatch: + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +permissions: + contents: write + +jobs: + timings: + runs-on: ubuntu-latest + container: + image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1 + options: --user 1001 + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 + - name: Setup Node.js + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 + with: + node-version-file: '.node-version' + - name: Install dependencies + uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6 + with: + runTests: false + - name: Cypress run + uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6 + id: cypress + with: + install: false + start: pnpm run dev:coverage + wait-on: 'http://localhost:9000' + browser: chrome + publish-summary: false + env: + VITEST_COVERAGE: true + CYPRESS_COMMIT: ${{ github.sha }} + SPLIT: 1 + SPLIT_INDEX: 0 + SPLIT_FILE: 'cypress/timings.json' + - name: Commit changes + uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9.1.4 + with: + add: 'cypress/timings.json' + author_name: 'github-actions[bot]' + author_email: '41898282+github-actions[bot]@users.noreply.github.com' + message: 'chore: update E2E timings' diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 2b91d078e..c5bbc6e62 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -28,7 +28,6 @@ env: ) || github.event.before }} - shouldRunParallel: ${{ secrets.CYPRESS_RECORD_KEY != '' && !(github.event_name == 'push' && github.ref == 'refs/heads/develop') }} jobs: cache: runs-on: ubuntu-latest @@ -39,7 +38,7 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 - name: Setup Node.js - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: node-version-file: '.node-version' - name: Cache snapshots @@ -59,7 +58,7 @@ jobs: - name: Install dependencies if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }} - uses: cypress-io/github-action@df7484c5ba85def7eef30db301afa688187bc378 # v6.7.2 + uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6 with: # just perform install runTests: false @@ -80,7 +79,7 @@ jobs: strategy: fail-fast: false matrix: - containers: [1, 2, 3, 4] + containers: [1, 2, 3, 4, 5] steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -88,7 +87,7 @@ jobs: # uses version from "packageManager" field in package.json - name: Setup Node.js - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: node-version-file: '.node-version' @@ -101,7 +100,7 @@ jobs: key: ${{ runner.os }}-snapshots-${{ env.targetHash }} - name: Install dependencies - uses: cypress-io/github-action@df7484c5ba85def7eef30db301afa688187bc378 # v6.7.2 + uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6 with: runTests: false @@ -117,11 +116,8 @@ jobs: # Install NPM dependencies, cache them correctly # and run all Cypress tests - name: Cypress run - uses: cypress-io/github-action@df7484c5ba85def7eef30db301afa688187bc378 # v6.7.2 + uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6 id: cypress - # If CYPRESS_RECORD_KEY is set, run in parallel on all containers - # Otherwise (e.g. if running from fork), we run on a single container only - if: ${{ env.shouldRunParallel == 'true' || ( matrix.containers == 1 ) }} with: install: false start: pnpm run dev:coverage @@ -129,16 +125,18 @@ jobs: browser: chrome # Disable recording if we don't have an API key # e.g. if this action was run from a fork - record: ${{ env.shouldRunParallel == 'true' }} - parallel: ${{ env.shouldRunParallel == 'true' }} + record: ${{ secrets.CYPRESS_RECORD_KEY != '' }} env: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} VITEST_COVERAGE: true CYPRESS_COMMIT: ${{ github.sha }} ARGOS_TOKEN: ${{ secrets.ARGOS_TOKEN }} - ARGOS_PARALLEL: ${{ env.shouldRunParallel == 'true' }} - ARGOS_PARALLEL_TOTAL: 4 + ARGOS_PARALLEL: true + ARGOS_PARALLEL_TOTAL: ${{ strategy.job-total }} ARGOS_PARALLEL_INDEX: ${{ matrix.containers }} + SPLIT: ${{ strategy.job-total }} + SPLIT_INDEX: ${{ strategy.job-index }} + SPLIT_FILE: 'cypress/timings.json' - name: Upload Coverage to Codecov uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index febd2f92d..24e7ee35d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -29,7 +29,7 @@ jobs: # uses version from "packageManager" field in package.json - name: Setup Node.js - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: cache: pnpm node-version-file: '.node-version' diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index ecb411b5c..587ddae08 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -28,7 +28,7 @@ jobs: - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 - name: Setup Node.js - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: cache: pnpm node-version-file: '.node-version' diff --git a/.github/workflows/release-preview-publish.yml b/.github/workflows/release-preview-publish.yml index 96556aa26..fa48d3659 100644 --- a/.github/workflows/release-preview-publish.yml +++ b/.github/workflows/release-preview-publish.yml @@ -16,7 +16,7 @@ jobs: - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 - name: Setup Node.js - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: cache: pnpm node-version-file: '.node-version' diff --git a/.github/workflows/release-preview.yml b/.github/workflows/release-preview.yml index 84808e44f..7b7dba987 100644 --- a/.github/workflows/release-preview.yml +++ b/.github/workflows/release-preview.yml @@ -31,7 +31,7 @@ jobs: - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 - name: Setup Node.js - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: cache: pnpm node-version-file: '.node-version' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3db5f6f37..4e8e9cd83 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 - name: Setup Node.js - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: cache: pnpm node-version-file: '.node-version' @@ -36,7 +36,7 @@ jobs: - name: Create Release Pull Request or Publish to npm id: changesets - uses: changesets/action@aba318e9165b45b7948c60273e0b72fce0a64eb9 # v1.4.7 + uses: changesets/action@3de3850952bec538fde60aac71731376e57b9b57 # v1.4.8 with: version: pnpm changeset:version publish: pnpm changeset:publish diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 0dee2e666..528e94045 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -16,11 +16,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: persist-credentials: false - name: Run analysis - uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 + uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 with: results_file: results.sarif results_format: sarif @@ -32,6 +32,6 @@ jobs: path: results.sarif retention-days: 5 - name: Upload to code-scanning - uses: github/codeql-action/upload-sarif@f0f3afee809481da311ca3a6ff1ff51d81dbeb24 # v3.26.4 + uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 with: sarif_file: results.sarif diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 026ca0fb7..7323ec027 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: # uses version from "packageManager" field in package.json - name: Setup Node.js - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 with: cache: pnpm node-version-file: '.node-version' diff --git a/cypress.config.ts b/cypress.config.ts index 3346b5549..b0257b9b2 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -1,8 +1,9 @@ -import { defineConfig } from 'cypress'; -import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin'; -import coverage from '@cypress/code-coverage/task'; import eyesPlugin from '@applitools/eyes-cypress'; import { registerArgosTask } from '@argos-ci/cypress/task'; +import coverage from '@cypress/code-coverage/task'; +import { defineConfig } from 'cypress'; +import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin'; +import cypressSplit from 'cypress-split'; export default eyesPlugin( defineConfig({ @@ -13,6 +14,7 @@ export default eyesPlugin( specPattern: 'cypress/integration/**/*.{js,ts}', setupNodeEvents(on, config) { coverage(on, config); + cypressSplit(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'); diff --git a/cypress/helpers/util.ts b/cypress/helpers/util.ts index 74b17cf05..52da4a72e 100644 --- a/cypress/helpers/util.ts +++ b/cypress/helpers/util.ts @@ -29,6 +29,7 @@ export const mermaidUrl = ( options: CypressMermaidConfig, api: boolean ): string => { + options.handDrawnSeed = 1; const codeObject: CodeObject = { code: graphStr, mermaid: options, diff --git a/cypress/integration/rendering/architecture.spec.ts b/cypress/integration/rendering/architecture.spec.ts index 1deb1f7da..bc2276352 100644 --- a/cypress/integration/rendering/architecture.spec.ts +++ b/cypress/integration/rendering/architecture.spec.ts @@ -173,7 +173,8 @@ describe.skip('architecture diagram', () => { }); }); -describe('architecture - external', () => { +// Skipped as the layout is not deterministic, and causes issues in E2E tests. +describe.skip('architecture - external', () => { it('should allow adding external icons', () => { urlSnapshotTest('http://localhost:9000/architecture-external.html'); }); diff --git a/cypress/integration/rendering/classDiagram-v2.spec.js b/cypress/integration/rendering/classDiagram-v2.spec.js index 258f8529f..0c5dbc04b 100644 --- a/cypress/integration/rendering/classDiagram-v2.spec.js +++ b/cypress/integration/rendering/classDiagram-v2.spec.js @@ -581,4 +581,63 @@ class C13["With Città foreign language"] { logLevel: 1, flowchart: { htmlLabels: false } } ); }); + + it('renders a class diagram with a generic class in a namespace', () => { + const diagramDefinition = ` + classDiagram-v2 + namespace Company.Project.Module { + class GenericClass~T~ { + +addItem(item: T) + +getItem() T + } + } + `; + + imgSnapshotTest(diagramDefinition); + }); + + it('renders a class diagram with nested namespaces and relationships', () => { + const diagramDefinition = ` + classDiagram-v2 + namespace Company.Project.Module.SubModule { + class Report { + +generatePDF(data: List) + +generateCSV(data: List) + } + } + namespace Company.Project.Module { + class Admin { + +generateReport() + } + } + Admin --> Report : generates + `; + + imgSnapshotTest(diagramDefinition); + }); + + it('renders a class diagram with multiple classes and relationships in a namespace', () => { + const diagramDefinition = ` + classDiagram-v2 + namespace Company.Project.Module { + class User { + +login(username: String, password: String) + +logout() + } + class Admin { + +addUser(user: User) + +removeUser(user: User) + +generateReport() + } + class Report { + +generatePDF(reportData: List) + +generateCSV(reportData: List) + } + } + Admin --> User : manages + Admin --> Report : generates + `; + + imgSnapshotTest(diagramDefinition); + }); }); diff --git a/cypress/integration/rendering/flowchart-handDrawn.spec.js b/cypress/integration/rendering/flowchart-handDrawn.spec.js index 10d6dde87..49c55c628 100644 --- a/cypress/integration/rendering/flowchart-handDrawn.spec.js +++ b/cypress/integration/rendering/flowchart-handDrawn.spec.js @@ -12,7 +12,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -30,7 +29,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: true }, fontFamily: 'courier', } @@ -47,7 +45,7 @@ describe('Flowchart HandDrawn', () => { C -->|Two| E[iPhone] C -->|Three| F[Car] `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -62,7 +60,7 @@ describe('Flowchart HandDrawn', () => { C -->|Two| E[\\iPhone\\] C -->|Three| F[Car] `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -78,7 +76,7 @@ describe('Flowchart HandDrawn', () => { classDef processHead fill:#888888,color:white,font-weight:bold,stroke-width:3px,stroke:#001f3f class 1A,1B,D,E processHead `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -107,7 +105,7 @@ describe('Flowchart HandDrawn', () => { 35(SAM.CommonFA.PopulationFME)-->39(SAM.CommonFA.ChargeDetails) 36(SAM.CommonFA.PremetricCost)-->39(SAM.CommonFA.ChargeDetails) `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -178,7 +176,7 @@ describe('Flowchart HandDrawn', () => { 9a072290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002 9a072290_1ec3_e711_8c5a_005056ad0002-->71082290_1ec3_e711_8c5a_005056ad0002 `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -187,7 +185,7 @@ describe('Flowchart HandDrawn', () => { ` graph TB;subgraph "number as labels";1;end; `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -199,7 +197,7 @@ describe('Flowchart HandDrawn', () => { a1-->a2 end `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -211,7 +209,7 @@ describe('Flowchart HandDrawn', () => { a1-->a2 end `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -246,7 +244,7 @@ describe('Flowchart HandDrawn', () => { style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -348,7 +346,7 @@ describe('Flowchart HandDrawn', () => { sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A; sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4FC27B48-A6F9-460A-A675-021F5854FE22; `, - { look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' } + { look: 'handDrawn', fontFamily: 'courier' } ); }); @@ -364,7 +362,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, listUrl: false, listId: 'color styling', fontFamily: 'courier', @@ -390,7 +387,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, listUrl: false, listId: 'color styling', fontFamily: 'courier', @@ -411,7 +407,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -435,7 +430,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -457,7 +451,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -471,7 +464,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -485,7 +477,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -500,7 +491,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -527,7 +517,6 @@ describe('Flowchart HandDrawn', () => { class A someclass;`, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -544,7 +533,7 @@ describe('Flowchart HandDrawn', () => { C -->|Two| E[iPhone] C -->|Three| F[fa:fa-car Car] `, - { look: 'handDrawn', handDrawnSeed: 1, flowchart: { nodeSpacing: 50 }, fontFamily: 'courier' } + { look: 'handDrawn', flowchart: { nodeSpacing: 50 }, fontFamily: 'courier' } ); }); @@ -560,7 +549,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { rankSpacing: '100' }, fontFamily: 'courier', } @@ -578,7 +566,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -603,7 +590,7 @@ describe('Flowchart HandDrawn', () => { click E "notes://do-your-thing/id" "other protocol test" click F "javascript:alert('test')" "script test" `, - { look: 'handDrawn', handDrawnSeed: 1, securityLevel: 'loose', fontFamily: 'courier' } + { look: 'handDrawn', securityLevel: 'loose', fontFamily: 'courier' } ); }); @@ -623,7 +610,7 @@ describe('Flowchart HandDrawn', () => { click B "index.html#link-clicked" "link test" click D testClick "click test" `, - { look: 'handDrawn', handDrawnSeed: 1, flowchart: { htmlLabels: true } } + { look: 'handDrawn', flowchart: { htmlLabels: true } } ); }); @@ -645,7 +632,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -664,7 +650,7 @@ describe('Flowchart HandDrawn', () => { class A myClass1 class D myClass2 `, - { look: 'handDrawn', handDrawnSeed: 1, flowchart: { htmlLabels: true } } + { look: 'handDrawn', flowchart: { htmlLabels: true } } ); }); @@ -682,7 +668,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -711,7 +696,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -728,7 +712,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -752,7 +735,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: false }, fontFamily: 'courier', } @@ -769,7 +751,7 @@ describe('Flowchart HandDrawn', () => { C -->|Two| E[iPhone] C -->|Three| F[fa:fa-car Car] `, - { look: 'handDrawn', handDrawnSeed: 1, flowchart: { diagramPadding: 0 } } + { look: 'handDrawn', flowchart: { diagramPadding: 0 } } ); }); @@ -804,7 +786,7 @@ describe('Flowchart HandDrawn', () => { `graph TD a["Haiya"]-->b `, - { look: 'handDrawn', handDrawnSeed: 1, htmlLabels: false, flowchart: { htmlLabels: false } } + { look: 'handDrawn', htmlLabels: false, flowchart: { htmlLabels: false } } ); }); it('FDH37: should render non-escaped with html labels', () => { @@ -814,7 +796,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -830,7 +811,7 @@ describe('Flowchart HandDrawn', () => { C -->|Two| E[iPhone] C -->|Three| F[fa:fa-car Car] `, - { look: 'handDrawn', handDrawnSeed: 1, flowchart: { useMaxWidth: true } } + { look: 'handDrawn', flowchart: { useMaxWidth: true } } ); cy.get('svg').should((svg) => { expect(svg).to.have.attr('width', '100%'); @@ -853,7 +834,7 @@ describe('Flowchart HandDrawn', () => { C -->|Two| E[iPhone] C -->|Three| F[fa:fa-car Car] `, - { look: 'handDrawn', handDrawnSeed: 1, flowchart: { useMaxWidth: false } } + { look: 'handDrawn', flowchart: { useMaxWidth: false } } ); cy.get('svg').should((svg) => { // const height = parseFloat(svg.attr('height')); @@ -874,7 +855,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -904,7 +884,6 @@ describe('Flowchart HandDrawn', () => { `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -919,7 +898,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -937,7 +915,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -977,7 +954,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -999,7 +975,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -1016,7 +991,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -1032,7 +1006,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose', @@ -1051,7 +1024,6 @@ graph TD `, { look: 'handDrawn', - handDrawnSeed: 1, flowchart: { htmlLabels: true }, securityLevel: 'loose', } diff --git a/cypress/integration/rendering/flowchart-shape-alias.spec.ts b/cypress/integration/rendering/flowchart-shape-alias.spec.ts new file mode 100644 index 000000000..86aef718c --- /dev/null +++ b/cypress/integration/rendering/flowchart-shape-alias.spec.ts @@ -0,0 +1,142 @@ +import { imgSnapshotTest } from '../../helpers/util.ts'; + +const aliasSet1 = ['process', 'rect', 'proc', 'rectangle'] as const; + +const aliasSet2 = ['event', 'rounded'] as const; + +const aliasSet3 = ['stadium', 'pill', 'terminal'] as const; + +const aliasSet4 = ['fr-rect', 'subproc', 'subprocess', 'framed-rectangle', 'subroutine'] as const; + +const aliasSet5 = ['db', 'database', 'cylinder', 'cyl'] as const; + +const aliasSet6 = ['diam', 'decision', 'diamond'] as const; + +const aliasSet7 = ['hex', 'hexagon', 'prepare'] as const; + +const aliasSet8 = ['lean-r', 'lean-right', 'in-out'] as const; + +const aliasSet9 = ['lean-l', 'lean-left', 'out-in'] as const; + +const aliasSet10 = ['trap-b', 'trapezoid-bottom', 'priority'] as const; + +const aliasSet11 = ['trap-t', 'trapezoid-top', 'manual'] as const; + +const aliasSet12 = ['dbl-circ', 'double-circle'] as const; + +const aliasSet13 = ['notched-rectangle', 'card', 'notch-rect'] as const; + +const aliasSet14 = [ + 'lin-rect', + 'lined-rectangle', + 'lin-proc', + 'lined-process', + 'shaded-process', +] as const; + +const aliasSet15 = ['sm-circ', 'small-circle', 'start'] as const; + +const aliasSet16 = ['fr-circ', 'framed-circle', 'stop'] as const; + +const aliasSet17 = ['fork', 'join'] as const; +// brace-r', 'braces' +const aliasSet18 = ['comment', 'brace-l'] as const; + +const aliasSet19 = ['bolt', 'com-link', 'lightning-bolt'] as const; + +const aliasSet20 = ['doc', 'document'] as const; + +const aliasSet21 = ['delay', 'half-rounded-rectangle'] as const; + +const aliasSet22 = ['h-cyl', 'das', 'horizontal-cylinder'] as const; + +const aliasSet23 = ['lin-cyl', 'disk', 'lined-cylinder'] as const; + +const aliasSet24 = ['curv-trap', 'display', 'curved-trapezoid'] as const; + +const aliasSet25 = ['div-rect', 'div-proc', 'divided-rectangle', 'divided-process'] as const; + +const aliasSet26 = ['extract', 'tri', 'triangle'] as const; + +const aliasSet27 = ['win-pane', 'internal-storage', 'window-pane'] as const; + +const aliasSet28 = ['f-circ', 'junction', 'filled-circle'] as const; + +const aliasSet29 = ['lin-doc', 'lined-document'] as const; + +const aliasSet30 = ['notch-pent', 'loop-limit', 'notched-pentagon'] as const; + +const aliasSet31 = ['flip-tri', 'manual-file', 'flipped-triangle'] as const; + +const aliasSet32 = ['sl-rect', 'manual-input', 'sloped-rectangle'] as const; + +const aliasSet33 = ['docs', 'documents', 'st-doc', 'stacked-document'] as const; + +const aliasSet34 = ['procs', 'processes', 'st-rect', 'stacked-rectangle'] as const; + +const aliasSet35 = ['flag', 'paper-tape'] as const; + +const aliasSet36 = ['bow-rect', 'stored-data', 'bow-tie-rectangle'] as const; + +const aliasSet37 = ['cross-circ', 'summary', 'crossed-circle'] as const; + +const aliasSet38 = ['tag-doc', 'tagged-document'] as const; + +const aliasSet39 = ['tag-rect', 'tag-proc', 'tagged-rectangle', 'tagged-process'] as const; + +const aliasSet40 = ['collate', 'hourglass'] as const; + +// Aggregate all alias sets into a single array +const aliasSets = [ + aliasSet1, + aliasSet2, + aliasSet3, + aliasSet4, + aliasSet5, + aliasSet6, + aliasSet7, + aliasSet8, + aliasSet9, + aliasSet10, + aliasSet11, + aliasSet12, + aliasSet13, + aliasSet14, + aliasSet15, + aliasSet16, + aliasSet17, + aliasSet18, + aliasSet19, + aliasSet20, + aliasSet21, + aliasSet22, + aliasSet23, + aliasSet24, + aliasSet25, + aliasSet26, + aliasSet27, + aliasSet28, + aliasSet29, + aliasSet30, + aliasSet31, + aliasSet32, + aliasSet33, + aliasSet34, + aliasSet35, + aliasSet36, + aliasSet37, + aliasSet38, + aliasSet39, +] as const; + +aliasSets.forEach((aliasSet) => { + describe(`Test ${aliasSet.join(',')} `, () => { + it(`All ${aliasSet.join(',')} should render same shape`, () => { + let flowchartCode = `flowchart \n`; + aliasSet.forEach((alias, index) => { + flowchartCode += ` n${index}@{ shape: ${alias}, label: "${alias}" }\n`; + }); + imgSnapshotTest(flowchartCode); + }); + }); +}); diff --git a/cypress/integration/rendering/iconShape.spec.ts b/cypress/integration/rendering/iconShape.spec.ts new file mode 100644 index 000000000..4c12c3fa3 --- /dev/null +++ b/cypress/integration/rendering/iconShape.spec.ts @@ -0,0 +1,143 @@ +import { imgSnapshotTest } from '../../helpers/util'; + +const looks = ['classic', 'handDrawn'] as const; +const directions = [ + 'TB', + //'BT', + 'LR', + // 'RL' +] as const; +const forms = [undefined, 'square', 'circle', 'rounded'] as const; +const labelPos = [undefined, 't', 'b'] as const; + +looks.forEach((look) => { + directions.forEach((direction) => { + forms.forEach((form) => { + labelPos.forEach((pos) => { + describe(`Test iconShape in ${form ? `${form} form,` : ''} ${look} look and dir ${direction} with label position ${pos ? pos : 'not defined'}`, () => { + it(`without label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'This is a label for icon shape'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with very long label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'This is a very very very very very long long long label for icon shape'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:true`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'This is **bold**
and strong for icon shape'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:false`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'This is **bold**
and strong for icon shape'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { + look, + htmlLabels: false, + flowchart: { htmlLabels: false }, + }); + }); + + it(`with styles`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'new icon shape'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + flowchartCode += ` style nAA fill:#f9f,stroke:#333,stroke-width:4px \n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with classDef`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` classDef customClazz fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5\n`; + flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'new icon shape'`; + if (form) { + flowchartCode += `, form: '${form}'`; + } + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + flowchartCode += ` nAA:::customClazz\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + }); + }); + }); + }); +}); + +describe('Test iconShape with different h', () => { + it('with different h', () => { + let flowchartCode = `flowchart TB\n`; + const icon = 'fa:bell'; + const iconHeight = 64; + flowchartCode += ` nA --> nAA@{ icon: '${icon}', label: 'icon with different h', h: ${iconHeight} }\n`; + imgSnapshotTest(flowchartCode); + }); +}); + +describe('Test colored iconShape', () => { + it('with no styles', () => { + let flowchartCode = `flowchart TB\n`; + const icon = 'fluent-emoji:tropical-fish'; + flowchartCode += ` nA --> nAA@{ icon: '${icon}', form: 'square', label: 'icon with color' }\n`; + imgSnapshotTest(flowchartCode); + }); + + it('with styles', () => { + let flowchartCode = `flowchart TB\n`; + const icon = 'fluent-emoji:tropical-fish'; + flowchartCode += ` nA --> nAA@{ icon: '${icon}', form: 'square', label: 'icon with color' }\n`; + flowchartCode += ` style nAA fill:#f9f,stroke:#333,stroke-width:4px \n`; + imgSnapshotTest(flowchartCode); + }); +}); diff --git a/cypress/integration/rendering/imageShape.spec.ts b/cypress/integration/rendering/imageShape.spec.ts new file mode 100644 index 000000000..d2e267149 --- /dev/null +++ b/cypress/integration/rendering/imageShape.spec.ts @@ -0,0 +1,103 @@ +import { imgSnapshotTest } from '../../helpers/util'; + +const looks = ['classic', 'handDrawn'] as const; +const directions = [ + 'TB', + //'BT', + 'LR', + // 'RL' +] as const; +const labelPos = [undefined, 't', 'b'] as const; + +looks.forEach((look) => { + directions.forEach((direction) => { + labelPos.forEach((pos) => { + describe(`Test imageShape in ${look} look and dir ${direction} with label position ${pos ? pos : 'not defined'}`, () => { + it(`without label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', w: '100', h: '100' }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'This is a label for image shape'`; + + flowchartCode += `, w: '100', h: '200'`; + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with very long label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'This is a very very very very very long long long label for image shape'`; + + flowchartCode += `, w: '100', h: '250'`; + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:true`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'This is **bold**
and strong for image shape'`; + + flowchartCode += `, w: '550', h: '200'`; + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { look, htmlLabels: true }); + }); + + it(`with markdown htmlLabels:false`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'This is **bold**
and strong for image shape'`; + flowchartCode += `, w: '250', h: '200'`; + + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + imgSnapshotTest(flowchartCode, { + look, + htmlLabels: false, + flowchart: { htmlLabels: false }, + }); + }); + + it(`with styles`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'new image shape'`; + flowchartCode += `, w: '550', h: '200'`; + + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + flowchartCode += ` style A fill:#f9f,stroke:#333,stroke-width:4px \n`; + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with classDef`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` classDef customClazz fill:#bbf,stroke:#f66,stroke-width:2px,color:#000000,stroke-dasharray: 5 5\n`; + flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'new image shape'`; + + flowchartCode += `, w: '500', h: '550'`; + if (pos) { + flowchartCode += `, pos: '${pos}'`; + } + flowchartCode += ` }\n`; + flowchartCode += ` A:::customClazz\n`; + imgSnapshotTest(flowchartCode, { look }); + }); + }); + }); + }); +}); diff --git a/cypress/integration/rendering/newShapes.spec.ts b/cypress/integration/rendering/newShapes.spec.ts new file mode 100644 index 000000000..6c71a3846 --- /dev/null +++ b/cypress/integration/rendering/newShapes.spec.ts @@ -0,0 +1,146 @@ +import { imgSnapshotTest } from '../../helpers/util.ts'; + +const looks = ['classic', 'handDrawn'] as const; +const directions = [ + 'TB', + //'BT', + 'LR', + //'RL' +] as const; +const newShapesSet1 = [ + 'triangle', + 'sloped-rectangle', + 'horizontal-cylinder', + 'flipped-triangle', + 'hourglass', +] as const; +const newShapesSet2 = [ + 'tagged-rectangle', + 'documents', + 'lightning-bolt', + 'filled-circle', + 'window-pane', +] as const; + +const newShapesSet3 = [ + 'curved-trapezoid', + 'bow-rect', + 'tagged-document', + 'divided-rectangle', + 'crossed-circle', +] as const; + +const newShapesSet4 = [ + 'document', + 'notched-pentagon', + 'lined-cylinder', + 'stacked-document', + 'half-rounded-rectangle', +] as const; + +const newShapesSet5 = [ + 'lined-document', + 'tagged-document', + 'brace-l', + 'comment', + 'braces', + 'brace-r', +] as const; + +const newShapesSet6 = ['brace-r', 'braces'] as const; +// Aggregate all shape sets into a single array +const newShapesSets = [ + newShapesSet1, + newShapesSet2, + newShapesSet3, + newShapesSet4, + newShapesSet5, + newShapesSet6, +]; + +looks.forEach((look) => { + directions.forEach((direction) => { + newShapesSets.forEach((newShapesSet) => { + describe(`Test ${newShapesSet.join(', ')} in ${look} look and dir ${direction}`, () => { + it(`without label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape} }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is a label for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`connect all shapes with each other`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index}${index}@{ shape: ${newShape}, label: 'This is a label for ${newShape} shape' }\n`; + }); + for (let i = 0; i < newShapesSet.length; i++) { + for (let j = i + 1; j < newShapesSet.length; j++) { + flowchartCode += ` n${i}${i} --> n${j}${j}\n`; + } + } + if (!(direction === 'TB' && look === 'handDrawn' && newShapesSet === newShapesSet1)) { + //skip this test, works in real. Need to look + imgSnapshotTest(flowchartCode, { look }); + } + }); + + it(`with very long label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is a very very very very very long long long label for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:true`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is **bold**
and strong for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:false`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is **bold**
and strong for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { + look, + htmlLabels: false, + flowchart: { htmlLabels: false }, + }); + }); + + it(`with styles`, () => { + let flowchartCode = `flowchart ${direction}\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'new ${newShape} shape' }\n`; + flowchartCode += ` style n${index}${index} fill:#f9f,stroke:#333,stroke-width:4px \n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with classDef`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` classDef customClazz fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5\n`; + newShapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'new ${newShape} shape' }\n`; + flowchartCode += ` n${index}${index}:::customClazz\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + }); + }); + }); +}); diff --git a/cypress/integration/rendering/oldShapes.spec.ts b/cypress/integration/rendering/oldShapes.spec.ts new file mode 100644 index 000000000..628e70ea8 --- /dev/null +++ b/cypress/integration/rendering/oldShapes.spec.ts @@ -0,0 +1,107 @@ +import { imgSnapshotTest } from '../../helpers/util'; + +const looks = ['classic', 'handDrawn'] as const; +const directions = [ + 'TB', + //'BT', + 'LR', + //'RL' +] as const; + +const shapesSet1 = ['text', 'card', 'lin-rect', 'diamond', 'hexagon'] as const; + +// removing labelRect, need have alias for it +const shapesSet2 = ['rounded', 'rect', 'start', 'stop'] as const; + +const shapesSet3 = ['fork', 'choice', 'note', 'stadium', 'odd'] as const; + +const shapesSet4 = ['subroutine', 'cylinder', 'circle', 'doublecircle', 'odd'] as const; + +const shapesSet5 = ['anchor', 'lean-r', 'lean-l', 'trap-t', 'trap-b'] as const; + +// Aggregate all shape sets into a single array +const shapesSets = [shapesSet1, shapesSet2, shapesSet3, shapesSet4, shapesSet5] as const; + +looks.forEach((look) => { + directions.forEach((direction) => { + shapesSets.forEach((shapesSet) => { + describe(`Test ${shapesSet.join(', ')} in ${look} look and dir ${direction}`, () => { + it(`without label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape} }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is a label for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`connect all shapes with each other`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index}${index}@{ shape: ${newShape}, label: 'This is a label for ${newShape} shape' }\n`; + }); + for (let i = 0; i < shapesSet.length; i++) { + for (let j = i + 1; j < shapesSet.length; j++) { + flowchartCode += ` n${i}${i} --> n${j}${j}\n`; + } + } + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with very long label`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is a very very very very very long long long label for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:true`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is **bold**
and strong for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with markdown htmlLabels:false`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is **bold**
and strong for ${newShape} shape' }\n`; + }); + imgSnapshotTest(flowchartCode, { + look, + htmlLabels: false, + flowchart: { htmlLabels: false }, + }); + }); + + it(`with styles`, () => { + let flowchartCode = `flowchart ${direction}\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'new ${newShape} shape' }\n`; + flowchartCode += ` style n${index}${index} fill:#f9f,stroke:#333,stroke-width:4px \n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + + it(`with classDef`, () => { + let flowchartCode = `flowchart ${direction}\n`; + flowchartCode += ` classDef customClazz fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5\n`; + shapesSet.forEach((newShape, index) => { + flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'new ${newShape} shape' }\n`; + flowchartCode += ` n${index}${index}:::customClazz\n`; + }); + imgSnapshotTest(flowchartCode, { look }); + }); + }); + }); + }); +}); diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index 80406b939..d93881018 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -83,7 +83,8 @@ -
+    
+
 ---
   title: hello2
   config:
@@ -242,8 +243,190 @@ stateDiagram-v2
 
 
 
-      
+
+
+---
+config:
+  look: neo
+---
+flowchart RL
+    subgraph "   "
+        A5@{ shape: manual-file, label: "a label"}
+        B5@{ shape: manual-input, label: "a label" }
+        C5@{ shape: mul-doc, label: "a label" }
+        D5@{ shape: mul-proc, label: "a label" }
+        E5@{ shape: paper-tape, label: "a label" }
+        B3@{ shape: das, label: "a label" }
+        C3@{ shape: disk, label: "a label" }
+        D4@{ shape: lin-doc, label: "a label" }
+        E4@{ shape: loop-limit, label: "a label" }
+    end
+    subgraph "   "
+        B6@{ shape: summary, label: "a label" }
+        C6@{ shape: tag-we-rect, label: "a label" }
+        D6@{ shape: tag-rect, label: "a label" }
+        A2@{ shape: fork}
+        B2@{ shape: hourglass }
+        C2@{ shape: comment, label: "I am a comment" }
+        D2@{ shape: bolt }
+        D3@{ shape: disp, label: "a label" }
+        C4@{ shape: junction, label: "a label" }
+        A4@{ shape: extract, label: "a label"}
+        B52[a fr]@{ shape: fr }
+    end
+    subgraph " "
+        A1@{ shape: text, label: This is a textblock}
+        B1@{ shape: card, label: "a label" }
+        C1@{ shape: lined-proc, label: "a label" }
+        D1@{ shape: start, label: "a label" }
+        E1@{ shape: stop, label: "a label" }
+        E2@{ shape: doc, label: "a label" }
+        A6@{ shape: stored-data, label: "a label"}
+        A3@{ shape: delay, label: "a label" }
+        E3@{ shape: div-proc, label: "a label" }
+        B4[a label]@{ shape: win-pane }
+    end
+      
+
+---
+  title: hello2
+  config:
+    look: handDrawn
+    elk:
+      
+---
+%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
+flowchart TD
+
+    A([Start]) -->|go to booking page| B("select
+    ISBS booking no")
+    A --> QQ{cancel booking}
+    A --> RR{no show}
+    A --> SS{change booking}
+    B -->C(wmpay_request_payment.request_type= 'partial',
+ wmpay_request_payment.status= 'paid',
+ pos_booking.booking_status= ‘partial’ and 'full_deposit')
+ style C text-align:left
+    C -->D{manage booking}
+
+    D -->|cancel|E[ระบบแสดงช่องให้กรอกเหตุผล]
+    E -->F{กดปุ่ม 'cancel' หรือไม่}
+    F -->|Yes|G[ระบบบันทึกค่าใหม่
+    และไม่สามารถแก้ไขข้อมูลได้]
+    F -->|No|H[กดปุ่ม 'close']
+    H -->|ระบบไม่เปลี่ยนแปลงข้อมูล|Z
+    G -->|ระบบส่งข้อมูล|I[(POS_database)]
+    I -->|pos_booking.booking_status='cancel'|Z([End])
+
+
+    D -->|no show|J[ระบบแสดงช่องให้กรอกเหตุผล]
+    J -->K{กดปุ่ม 'noshow' หรือไม่}
+    K -->|Yes|L[ระบบสร้างใบเสร็จอัตโนมัติ
+    Product_id: 439,
+    ItemName: no show]
+     style L text-align:left
+
+     K -->|No|O[กดปุ่ม 'close']
+     O -->|ระบบไม่เปลี่ยนแปลงข้อมูล|Z
+    L -->M[ระบบบันทึกค่าใหม่]
+    M -->|ระบบส่งข้อมูล|N[(POS_database)]
+    N -->|pos_booking.booking_status=‘noshow’|Z
+
+
+
+
+
+---
+  title: hello2
+  config:
+    look: handDrawn
+    layout: dagre
+    elk:
+        nodePlacementStrategy: BRANDES_KOEPF
+---
+flowchart
+  A --> A
+  subgraph A
+    B --> B
+    subgraph B
+      C
+    end
+  end
+
+
+
+
+---
+config:
+  look: handdrawn
+  flowchart:
+    htmlLabels: true
+---
+flowchart
+      A[I am a long text, where do I go??? handdrawn - true]
+
+ +
+
+---
+config:
+  flowchart:
+    htmlLabels: false
+---
+flowchart
+      A[I am a long text, where do I go??? classic - false]
+
+
+---
+config:
+  flowchart:
+    htmlLabels: true
+---
+flowchart
+      A[I am a long text, where do I go??? classic - true]
+
+
+
+flowchart LR
+    id1(Start)-->id2(Stop)
+    style id1 fill:#f9f,stroke:#333,stroke-width:4px
+    style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
+
+
+    
+ +
+      flowchart LR
+    A:::foo & B:::bar --> C:::foobar
+    classDef foo stroke:#f00
+    classDef bar stroke:#0f0
+    classDef ash color:red
+    class C ash
+    style C stroke:#00f, fill:black
+
+    
+ +
+      stateDiagram
+    A:::foo
+    B:::bar --> C:::foobar
+    classDef foo stroke:#f00
+    classDef bar stroke:#0f0
+    style C stroke:#00f, fill:black, color:white
+
+    
+ +
+flowchart TB
+  A@{
+    label: "aksljhf kasjdh"
+  }
+    
+ + diff --git a/cypress/platform/viewer.js b/cypress/platform/viewer.js index 77da253c2..a9d4d2d81 100644 --- a/cypress/platform/viewer.js +++ b/cypress/platform/viewer.js @@ -50,6 +50,60 @@ const contentLoaded = async function () { mermaid.registerLayoutLoaders(layouts); mermaid.initialize(graphObj.mermaid); + const staticBellIconPack = { + prefix: 'fa6-regular', + icons: { + bell: { + body: '', + width: 448, + }, + }, + width: 512, + height: 512, + }; + /* MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE */ + const staticAwsLogoIconPack = { + prefix: 'fluent-emoji', + icons: { + 'tropical-fish': { + width: 32, + height: 32, + body: '', + }, + }, + width: 256, + height: 256, + }; + mermaid.registerIconPacks([ + { + name: 'fa', + loader: () => staticBellIconPack, + }, + { + name: 'fluent-emoji', + loader: () => staticAwsLogoIconPack, + }, + ]); await mermaid.run(); } }; diff --git a/cypress/timings.json b/cypress/timings.json new file mode 100644 index 000000000..3455d82fc --- /dev/null +++ b/cypress/timings.json @@ -0,0 +1,152 @@ +{ + "durations": [ + { + "spec": "cypress/integration/other/configuration.spec.js", + "duration": 4989 + }, + { + "spec": "cypress/integration/other/external-diagrams.spec.js", + "duration": 1382 + }, + { + "spec": "cypress/integration/other/ghsa.spec.js", + "duration": 3178 + }, + { + "spec": "cypress/integration/other/iife.spec.js", + "duration": 1372 + }, + { + "spec": "cypress/integration/other/interaction.spec.js", + "duration": 8998 + }, + { + "spec": "cypress/integration/other/rerender.spec.js", + "duration": 1249 + }, + { + "spec": "cypress/integration/other/xss.spec.js", + "duration": 25664 + }, + { + "spec": "cypress/integration/rendering/appli.spec.js", + "duration": 1928 + }, + { + "spec": "cypress/integration/rendering/architecture.spec.ts", + "duration": 2330 + }, + { + "spec": "cypress/integration/rendering/block.spec.js", + "duration": 11156 + }, + { + "spec": "cypress/integration/rendering/c4.spec.js", + "duration": 3418 + }, + { + "spec": "cypress/integration/rendering/classDiagram-v2.spec.js", + "duration": 14866 + }, + { + "spec": "cypress/integration/rendering/classDiagram.spec.js", + "duration": 9894 + }, + { + "spec": "cypress/integration/rendering/conf-and-directives.spec.js", + "duration": 5778 + }, + { + "spec": "cypress/integration/rendering/current.spec.js", + "duration": 1690 + }, + { + "spec": "cypress/integration/rendering/erDiagram.spec.js", + "duration": 9144 + }, + { + "spec": "cypress/integration/rendering/errorDiagram.spec.js", + "duration": 1951 + }, + { + "spec": "cypress/integration/rendering/flowchart-elk.spec.js", + "duration": 2196 + }, + { + "spec": "cypress/integration/rendering/flowchart-handDrawn.spec.js", + "duration": 21029 + }, + { + "spec": "cypress/integration/rendering/flowchart-shape-alias.spec.ts", + "duration": 16087 + }, + { + "spec": "cypress/integration/rendering/flowchart-v2.spec.js", + "duration": 27465 + }, + { + "spec": "cypress/integration/rendering/flowchart.spec.js", + "duration": 20035 + }, + { + "spec": "cypress/integration/rendering/gantt.spec.js", + "duration": 11366 + }, + { + "spec": "cypress/integration/rendering/gitGraph.spec.js", + "duration": 34025 + }, + { + "spec": "cypress/integration/rendering/iconShape.spec.ts", + "duration": 185902 + }, + { + "spec": "cypress/integration/rendering/imageShape.spec.ts", + "duration": 41631 + }, + { + "spec": "cypress/integration/rendering/info.spec.ts", + "duration": 1736 + }, + { + "spec": "cypress/integration/rendering/journey.spec.js", + "duration": 2247 + }, + { + "spec": "cypress/integration/rendering/katex.spec.js", + "duration": 2144 + }, + { + "spec": "cypress/integration/rendering/marker_unique_id.spec.js", + "duration": 1646 + }, + { + "spec": "cypress/integration/rendering/mindmap.spec.ts", + "duration": 6406 + }, + { + "spec": "cypress/integration/rendering/newShapes.spec.ts", + "duration": 107219 + }, + { + "spec": "cypress/integration/rendering/stateDiagram.spec.js", + "duration": 15834 + }, + { + "spec": "cypress/integration/rendering/theme.spec.js", + "duration": 33240 + }, + { + "spec": "cypress/integration/rendering/timeline.spec.ts", + "duration": 7122 + }, + { + "spec": "cypress/integration/rendering/xyChart.spec.js", + "duration": 11127 + }, + { + "spec": "cypress/integration/rendering/zenuml.spec.js", + "duration": 2391 + } + ] +} diff --git a/demos/classchart.html b/demos/classchart.html index f04fa5b5f..980ea5098 100644 --- a/demos/classchart.html +++ b/demos/classchart.html @@ -159,30 +159,87 @@ class People List~List~Person~~
-
     classDiagram
-      A1 --> B1
-      namespace A {
-        class A1 {
-          +foo : string
-        }
-        class A2 {
-          +bar : int
+      namespace Company.Project.Module {
+        class GenericClass~T~ {
+          +addItem(item: T)
+          +getItem() T
         }
       }
-      namespace B {
-        class B1 {
-          +foo : bool
-        }
-        class B2 {
-          +bar : float
-        }
-      }
-      A2 --> B2
     

- +
+    classDiagram
+      namespace Company.Project.Module.SubModule {
+        class Report {
+          +generatePDF(data: List)
+          +generateCSV(data: List)
+        }
+      }
+      namespace Company.Project.Module {
+        class Admin {
+          +generateReport()
+        }
+      }
+      Admin --> Report : generates
+    
+
+    classDiagram
+      namespace Company.Project.Module {
+        class User {
+          +login(username: String, password: String)
+          +logout()
+        }
+        class Admin {
+          +addUser(user: User)
+          +removeUser(user: User)
+          +generateReport()
+        }
+        class Report {
+          +generatePDF(reportData: List)
+          +generateCSV(reportData: List)
+        }
+      }
+      Admin --> User : manages
+      Admin --> Report : generates
+    
+
+
+    classDiagram
+      namespace Shapes {
+        class Shape {
+          +calculateArea() double
+        }
+        class Circle {
+          +double radius
+        }
+        class Square {
+          +double side
+        }
+      }
+      
+      Shape <|-- Circle
+      Shape <|-- Square
+      
+      namespace Vehicles {
+        class Vehicle {
+          +String brand
+        }
+        class Car {
+          +int horsepower
+        }
+        class Bike {
+          +boolean hasGears
+        }
+      }
+      
+      Vehicle <|-- Car
+      Vehicle <|-- Bike
+      Car --> Circle : "Logo Shape"
+      Bike --> Square : "Logo Shape"
+                  
+