From 4464703b7b4d7b9f8a59eed552f354a4071575b1 Mon Sep 17 00:00:00 2001 From: pengzhanbo Date: Sat, 12 Oct 2024 02:09:15 +0800 Subject: [PATCH] test: add unit test (#262) * test: add unit test * chore: tweak * chore: tweak --- .github/workflows/test.yml | 37 + .gitignore | 2 + package.json | 8 +- .../__snapshots__/bilibiliPlugin.spec.ts.snap | 10 + .../__snapshots__/caniusePlugin.spec.ts.snap | 90 +++ .../codeSandboxPlugin.spec.ts.snap | 9 + .../__snapshots__/codeTabsPlugin.spec.ts.snap | 81 +++ .../__snapshots__/codepenPlugin.spec.ts.snap | 9 + .../__snapshots__/fileTreePlugin.spec.ts.snap | 66 ++ .../__snapshots__/iconsPlugin.spec.ts.snap | 108 +++ .../__snapshots__/jsfiddlePlugin.spec.ts.snap | 9 + .../__snapshots__/npmToPlugin.spec.ts.snap | 361 ++++++++++ .../__snapshots__/pdfPlugin.spec.ts.snap | 12 + .../__snapshots__/plotPlugin.spec.ts.snap | 38 ++ .../__snapshots__/youtubePlugin.spec.ts.snap | 10 + .../__test__/alignPlugin.spec.ts | 13 + .../__test__/bilibiliPlugin.spec.ts | 44 ++ .../__test__/caniusePlugin.spec.ts | 73 ++ .../__test__/codeSandboxPlugin.spec.ts | 40 ++ .../__test__/codeTabsPlugin.spec.ts | 79 +++ .../__test__/codepenPlugin.spec.ts | 38 ++ .../__test__/fileTreePlugin.spec.ts | 58 ++ .../plugin-md-power/__test__/findIcon.spec.ts | 48 ++ .../__test__/iconsPlugin.spec.ts | 48 ++ .../__test__/jsfiddlePlugin.spec.ts | 40 ++ .../__test__/npmToPlugin.spec.ts | 131 ++++ .../__test__/parseRect.spec.ts | 20 + .../__test__/pdfPlugin.spec.ts | 47 ++ .../__test__/plotPlugin.spec.ts | 22 + .../__test__/resolveAttrs.spec.ts | 35 + .../__test__/timeToSeconds.spec.ts | 26 + .../__test__/youtubePlugin.spec.ts | 44 ++ .../src/node/container/codeTabs.ts | 22 +- .../src/node/container/fileTree.ts | 4 +- .../src/node/container/npmTo.ts | 69 +- .../plugin-md-power/src/node/embed/caniuse.ts | 5 +- .../src/node/embed/code/codeSandbox.ts | 2 +- .../src/node/embed/code/codepen.ts | 10 +- .../src/node/embed/code/jsfiddle.ts | 4 +- plugins/plugin-md-power/src/node/embed/pdf.ts | 2 +- .../src/node/embed/video/bilibili.ts | 4 +- .../src/node/embed/video/youtube.ts | 2 +- .../src/node/fileIcons/findIcon.ts | 9 +- .../plugin-md-power/src/node/inline/icons.ts | 9 +- .../plugin-md-power/src/node/utils/nanoid.ts | 3 + .../src/node/utils/resolveAttrs.ts | 2 +- .../src/node/utils/timeToSeconds.ts | 5 +- plugins/plugin-md-power/src/shared/plot.ts | 2 +- pnpm-lock.yaml | 641 +++++++++++++++++- vitest.config.ts | 12 + 50 files changed, 2379 insertions(+), 84 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 plugins/plugin-md-power/__test__/__snapshots__/bilibiliPlugin.spec.ts.snap create mode 100644 plugins/plugin-md-power/__test__/__snapshots__/caniusePlugin.spec.ts.snap create mode 100644 plugins/plugin-md-power/__test__/__snapshots__/codeSandboxPlugin.spec.ts.snap create mode 100644 plugins/plugin-md-power/__test__/__snapshots__/codeTabsPlugin.spec.ts.snap create mode 100644 plugins/plugin-md-power/__test__/__snapshots__/codepenPlugin.spec.ts.snap create mode 100644 plugins/plugin-md-power/__test__/__snapshots__/fileTreePlugin.spec.ts.snap create mode 100644 plugins/plugin-md-power/__test__/__snapshots__/iconsPlugin.spec.ts.snap create mode 100644 plugins/plugin-md-power/__test__/__snapshots__/jsfiddlePlugin.spec.ts.snap create mode 100644 plugins/plugin-md-power/__test__/__snapshots__/npmToPlugin.spec.ts.snap create mode 100644 plugins/plugin-md-power/__test__/__snapshots__/pdfPlugin.spec.ts.snap create mode 100644 plugins/plugin-md-power/__test__/__snapshots__/plotPlugin.spec.ts.snap create mode 100644 plugins/plugin-md-power/__test__/__snapshots__/youtubePlugin.spec.ts.snap create mode 100644 plugins/plugin-md-power/__test__/alignPlugin.spec.ts create mode 100644 plugins/plugin-md-power/__test__/bilibiliPlugin.spec.ts create mode 100644 plugins/plugin-md-power/__test__/caniusePlugin.spec.ts create mode 100644 plugins/plugin-md-power/__test__/codeSandboxPlugin.spec.ts create mode 100644 plugins/plugin-md-power/__test__/codeTabsPlugin.spec.ts create mode 100644 plugins/plugin-md-power/__test__/codepenPlugin.spec.ts create mode 100644 plugins/plugin-md-power/__test__/fileTreePlugin.spec.ts create mode 100644 plugins/plugin-md-power/__test__/findIcon.spec.ts create mode 100644 plugins/plugin-md-power/__test__/iconsPlugin.spec.ts create mode 100644 plugins/plugin-md-power/__test__/jsfiddlePlugin.spec.ts create mode 100644 plugins/plugin-md-power/__test__/npmToPlugin.spec.ts create mode 100644 plugins/plugin-md-power/__test__/parseRect.spec.ts create mode 100644 plugins/plugin-md-power/__test__/pdfPlugin.spec.ts create mode 100644 plugins/plugin-md-power/__test__/plotPlugin.spec.ts create mode 100644 plugins/plugin-md-power/__test__/resolveAttrs.spec.ts create mode 100644 plugins/plugin-md-power/__test__/timeToSeconds.spec.ts create mode 100644 plugins/plugin-md-power/__test__/youtubePlugin.spec.ts create mode 100644 plugins/plugin-md-power/src/node/utils/nanoid.ts create mode 100644 vitest.config.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..dbfec435 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,37 @@ +name: Test + +on: + push: + branches: [main] + + pull_request: + branches: [main] + +jobs: + unit-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + + - name: Install deps + run: pnpm install --frozen-lockfile + + - name: Unit Test + env: + NODE_OPTIONS: --max_old_space_size=8192 + run: pnpm run test --run + + - name: Upload coverage + if: github.ref == 'refs/heads/main' + uses: codecov/codecov-action@v4 diff --git a/.gitignore b/.gitignore index aaf239c5..f898f04e 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ dist/ *.log *.tsbuildinfo .mind + +coverage/ diff --git a/package.json b/package.json index c3f955a3..56c7460c 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "lint:fix": "pnpm lint:check --fix && pnpm lint:css --fix", "lint:check": "eslint .", "lint:css": "stylelint **/*.{css,vue}", + "test": "cross-env TZ=Etc/UTC vitest --coverage", "prepare": "husky", "release": "pnpm release:check && pnpm release:version && pnpm -r publish", "release:changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", @@ -45,19 +46,23 @@ "@types/lodash.merge": "^4.6.9", "@types/node": "20.12.10", "@types/webpack-env": "^1.18.5", + "@vitest/coverage-istanbul": "^2.1.2", "bumpp": "^9.6.1", "commitizen": "^4.3.1", "conventional-changelog-cli": "^5.0.0", "cpx2": "^8.0.0", + "cross-env": "7.0.3", "cz-conventional-changelog": "^3.3.0", "eslint": "^9.12.0", "husky": "^9.1.6", "lint-staged": "^15.2.10", + "markdown-it": "^14.1.0", "rimraf": "^6.0.1", "stylelint": "^16.9.0", "tsconfig-vuepress": "^5.2.0", "tsup": "^8.3.0", "typescript": "^5.6.2", + "vitest": "^2.1.2", "wait-on": "^8.0.1" }, "resolutions": { @@ -65,7 +70,8 @@ }, "lint-staged": { "*": "eslint --fix", - "*.{css,vue}": "stylelint --fix" + "*.{css,vue}": "stylelint --fix", + "*.{js,ts,mjs,cjs}": "cross-env TZ=Etc/UTC vitest related --run" }, "config": { "commitizen": { diff --git a/plugins/plugin-md-power/__test__/__snapshots__/bilibiliPlugin.spec.ts.snap b/plugins/plugin-md-power/__test__/__snapshots__/bilibiliPlugin.spec.ts.snap new file mode 100644 index 00000000..d76585fc --- /dev/null +++ b/plugins/plugin-md-power/__test__/__snapshots__/bilibiliPlugin.spec.ts.snap @@ -0,0 +1,10 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`bilibiliPlugin > should not work 1`] = ` +"

@[bilibili]xxx

+

@[ bilibili]BV12345

+

@[bilibili](BV12345

+" +`; + +exports[`bilibiliPlugin > should work 1`] = `""`; diff --git a/plugins/plugin-md-power/__test__/__snapshots__/caniusePlugin.spec.ts.snap b/plugins/plugin-md-power/__test__/__snapshots__/caniusePlugin.spec.ts.snap new file mode 100644 index 00000000..46e510e3 --- /dev/null +++ b/plugins/plugin-md-power/__test__/__snapshots__/caniusePlugin.spec.ts.snap @@ -0,0 +1,90 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`caniusePlugin > should not work 1`] = `""`; + +exports[`caniusePlugin > should not work 2`] = ` +"

@[caniuse]xxx

+" +`; + +exports[`caniusePlugin > should not work 3`] = ` +"

@ caniuse

+" +`; + +exports[`caniusePlugin > should not work 4`] = ` +"

@[caniuse](xxx

+" +`; + +exports[`caniusePlugin > should not work 5`] = ` +"

@[caniuse](

+" +`; + +exports[`caniusePlugin > should not work 6`] = ` +"

@[caniuse

+" +`; + +exports[`caniusePlugin > should not work 7`] = ` +"

@caniuse)

+" +`; + +exports[`caniusePlugin > should not work 8`] = ` +"

@caniuseee)

+" +`; + +exports[`caniusePlugin > should work 1`] = `""`; + +exports[`caniusePlugin > should work 2`] = ` +"

+ + + Data on support for the feature feature across the major browsers from caniuse.com +

" +`; + +exports[`caniusePlugin > should work 3`] = `""`; + +exports[`caniusePlugin > should work 4`] = `""`; + +exports[`caniusePlugin > should work 5`] = `""`; + +exports[`caniusePlugin > should work 6`] = `""`; + +exports[`caniusePlugin > should work with options 1`] = ` +"

+ + + Data on support for the feature feature across the major browsers from caniuse.com +

" +`; + +exports[`caniusePlugin > should work with options 2`] = `""`; + +exports[`caniusePlugin > should work with options 3`] = `""`; + +exports[`legacyCaniuse > should work 1`] = `""`; + +exports[`legacyCaniuse > should work 2`] = `""`; + +exports[`legacyCaniuse > should work 3`] = `""`; + +exports[`legacyCaniuse > should work with unknown mode 1`] = ` +"

+ + + Data on support for the feature feature across the major browsers from caniuse.com +

" +`; + +exports[`legacyCaniuse > should work with unknown mode 2`] = ` +"

+ + + Data on support for the feature{-2,4} feature across the major browsers from caniuse.com +

" +`; diff --git a/plugins/plugin-md-power/__test__/__snapshots__/codeSandboxPlugin.spec.ts.snap b/plugins/plugin-md-power/__test__/__snapshots__/codeSandboxPlugin.spec.ts.snap new file mode 100644 index 00000000..71e9aaee --- /dev/null +++ b/plugins/plugin-md-power/__test__/__snapshots__/codeSandboxPlugin.spec.ts.snap @@ -0,0 +1,9 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`codeSandboxPlugin > should not work 1`] = ` +"

@[codesandbox]xxx

+

@[codesandbox embed](

+" +`; + +exports[`codeSandboxPlugin > should work 1`] = `""`; diff --git a/plugins/plugin-md-power/__test__/__snapshots__/codeTabsPlugin.spec.ts.snap b/plugins/plugin-md-power/__test__/__snapshots__/codeTabsPlugin.spec.ts.snap new file mode 100644 index 00000000..fb07abcd --- /dev/null +++ b/plugins/plugin-md-power/__test__/__snapshots__/codeTabsPlugin.spec.ts.snap @@ -0,0 +1,81 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`codeTabsPlugin > should work with default 1`] = ` +"" +`; + +exports[`codeTabsPlugin > should work with no icon 1`] = ` +"" +`; + +exports[`codeTabsPlugin > should work with options: \`{ named: false, extensions: false }\` 1`] = ` +"" +`; + +exports[`codeTabsPlugin > should work with options: { named: [npm,pnpm,yarn], extensions: [.js,.ts] } 1`] = ` +"" +`; diff --git a/plugins/plugin-md-power/__test__/__snapshots__/codepenPlugin.spec.ts.snap b/plugins/plugin-md-power/__test__/__snapshots__/codepenPlugin.spec.ts.snap new file mode 100644 index 00000000..a8832100 --- /dev/null +++ b/plugins/plugin-md-power/__test__/__snapshots__/codepenPlugin.spec.ts.snap @@ -0,0 +1,9 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`codepenPlugin > should not work 1`] = ` +"

@[codepen]xxx

+

@[codepen preview](

+" +`; + +exports[`codepenPlugin > should work 1`] = `""`; diff --git a/plugins/plugin-md-power/__test__/__snapshots__/fileTreePlugin.spec.ts.snap b/plugins/plugin-md-power/__test__/__snapshots__/fileTreePlugin.spec.ts.snap new file mode 100644 index 00000000..b39ac60a --- /dev/null +++ b/plugins/plugin-md-power/__test__/__snapshots__/fileTreePlugin.spec.ts.snap @@ -0,0 +1,66 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`fileTreePlugin > should work with default options 1`] = ` +"
    +docs +
      +README.md +foo.md +
    +
    +src +
      +client +
        +components +
          +Navbar.vue +
        +
        +index.ts# comment +
      +
      +node +
        +index.ts +
      +
      +
    +
    +.gitignore +package.json +
+

files

    +src +
      +js +
        + +
      +
      +vue +css +
    +
    +README.md +
+
    +docs +src +
      +a.js +b.ts +
    +
    +README.md +
+
    +
  • +
  • +
      +
    • +
    +
  • +
+
" +`; diff --git a/plugins/plugin-md-power/__test__/__snapshots__/iconsPlugin.spec.ts.snap b/plugins/plugin-md-power/__test__/__snapshots__/iconsPlugin.spec.ts.snap new file mode 100644 index 00000000..d9a16e9e --- /dev/null +++ b/plugins/plugin-md-power/__test__/__snapshots__/iconsPlugin.spec.ts.snap @@ -0,0 +1,108 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`iconsPlugin > should not work with invalid icon 1`] = ` +"

:[ mdi:11 ]:

+" +`; + +exports[`iconsPlugin > should not work with invalid icon 2`] = ` +"

:[]:

+" +`; + +exports[`iconsPlugin > should not work with invalid icon 3`] = ` +"

:[]&

+" +`; + +exports[`iconsPlugin > should not work with invalid icon 4`] = ` +"

:[:[

+" +`; + +exports[`iconsPlugin > should not work with invalid icon 5`] = ` +"

:[mdi:11

+" +`; + +exports[`iconsPlugin > should work 1`] = ` +"

+" +`; + +exports[`iconsPlugin > should work 2`] = ` +"

strong

+" +`; + +exports[`iconsPlugin > should work 3`] = ` +"

strong + +

+" +`; + +exports[`iconsPlugin > should work with options 1`] = ` +"

+" +`; + +exports[`iconsPlugin > should work with options 2`] = ` +"

strong

+" +`; + +exports[`iconsPlugin > should work with single icon options 1`] = ` +"

+" +`; + +exports[`iconsPlugin > should work with single icon options 2`] = ` +"

+" +`; + +exports[`iconsPlugin > should work with single icon options 3`] = ` +"

+" +`; + +exports[`iconsPlugin > should work with single icon options 4`] = ` +"

+" +`; + +exports[`iconsPlugin > should work with single icon options 5`] = ` +"

+" +`; + +exports[`iconsPlugin > should work with single icon options 6`] = ` +"

+" +`; + +exports[`iconsPlugin > should work with single icon options 7`] = ` +"

+" +`; + +exports[`iconsPlugin > should work with single icon options 8`] = ` +"

+" +`; + +exports[`iconsPlugin > should work with single icon options 9`] = ` +"

+" +`; + +exports[`iconsPlugin > should work with single icon options 10`] = ` +"

+" +`; + +exports[`iconsPlugin > should work with single icon options 11`] = ` +"

+" +`; diff --git a/plugins/plugin-md-power/__test__/__snapshots__/jsfiddlePlugin.spec.ts.snap b/plugins/plugin-md-power/__test__/__snapshots__/jsfiddlePlugin.spec.ts.snap new file mode 100644 index 00000000..528bb0a7 --- /dev/null +++ b/plugins/plugin-md-power/__test__/__snapshots__/jsfiddlePlugin.spec.ts.snap @@ -0,0 +1,9 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`codeSandboxPlugin > should not work 1`] = ` +"

@[jsfiddle]xxx

+

@[jsfiddle](

+" +`; + +exports[`codeSandboxPlugin > should work 1`] = `""`; diff --git a/plugins/plugin-md-power/__test__/__snapshots__/npmToPlugin.spec.ts.snap b/plugins/plugin-md-power/__test__/__snapshots__/npmToPlugin.spec.ts.snap new file mode 100644 index 00000000..33523420 --- /dev/null +++ b/plugins/plugin-md-power/__test__/__snapshots__/npmToPlugin.spec.ts.snap @@ -0,0 +1,361 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`npmToPlugin > should work width options: [npm, yarn, pnpm] 1`] = ` +"

anything

+
+" +`; + +exports[`npmToPlugin > should work width options: { tabs: [npm, yarn, pnpm] } 1`] = ` +"

anything

+
+" +`; + +exports[`npmToPlugin > should work with default options 1`] = ` +"

anything

+
+" +`; diff --git a/plugins/plugin-md-power/__test__/__snapshots__/pdfPlugin.spec.ts.snap b/plugins/plugin-md-power/__test__/__snapshots__/pdfPlugin.spec.ts.snap new file mode 100644 index 00000000..46b628a5 --- /dev/null +++ b/plugins/plugin-md-power/__test__/__snapshots__/pdfPlugin.spec.ts.snap @@ -0,0 +1,12 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`pdfPlugin > should not work 1`] = ` +"

@[pdf]xxx

+

@ pdf

+

@[pdf]

+" +`; + +exports[`pdfPlugin > should work 1`] = `""`; + +exports[`pdfPlugin > should work 2`] = `""`; diff --git a/plugins/plugin-md-power/__test__/__snapshots__/plotPlugin.spec.ts.snap b/plugins/plugin-md-power/__test__/__snapshots__/plotPlugin.spec.ts.snap new file mode 100644 index 00000000..0a94af09 --- /dev/null +++ b/plugins/plugin-md-power/__test__/__snapshots__/plotPlugin.spec.ts.snap @@ -0,0 +1,38 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`plotPlugin > should not work with invalid tag 1`] = ` +"

!!!!

+" +`; + +exports[`plotPlugin > should not work with invalid tag 2`] = ` +"

!!plot!

+" +`; + +exports[`plotPlugin > should not work with invalid tag 3`] = ` +"

!!!

+" +`; + +exports[`plotPlugin > should not work with invalid tag 4`] = ` +"

!! plot !!

+" +`; + +exports[`plotPlugin > should work 1`] = ` +"

plot

+" +`; + +exports[`plotPlugin > should work 2`] = ` +"

hidden: plot strong

+" +`; + +exports[`plotPlugin > should work 3`] = ` +"

hidden:
+plot
+plot

+" +`; diff --git a/plugins/plugin-md-power/__test__/__snapshots__/youtubePlugin.spec.ts.snap b/plugins/plugin-md-power/__test__/__snapshots__/youtubePlugin.spec.ts.snap new file mode 100644 index 00000000..e181a063 --- /dev/null +++ b/plugins/plugin-md-power/__test__/__snapshots__/youtubePlugin.spec.ts.snap @@ -0,0 +1,10 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`youtubePlugin > should not work 1`] = ` +"

@[youtube]xxx

+

@[ youtube]123456

+

@ youtube

+" +`; + +exports[`youtubePlugin > should work 1`] = `""`; diff --git a/plugins/plugin-md-power/__test__/alignPlugin.spec.ts b/plugins/plugin-md-power/__test__/alignPlugin.spec.ts new file mode 100644 index 00000000..0b4ae114 --- /dev/null +++ b/plugins/plugin-md-power/__test__/alignPlugin.spec.ts @@ -0,0 +1,13 @@ +import MarkdownIt from 'markdown-it' +import { describe, expect, it } from 'vitest' +import { alignPlugin } from '../src/node/container/align.js' + +describe('alignPlugin', () => { + const md = new MarkdownIt().use(alignPlugin) + it('should work', () => { + expect(md.render(':::left\n:::')).toContain('style="text-align:left"') + expect(md.render(':::center\n:::')).toContain('style="text-align:center"') + expect(md.render(':::right\n:::')).toContain('style="text-align:right"') + expect(md.render(':::justify\n:::')).toContain('style="text-align:justify"') + }) +}) diff --git a/plugins/plugin-md-power/__test__/bilibiliPlugin.spec.ts b/plugins/plugin-md-power/__test__/bilibiliPlugin.spec.ts new file mode 100644 index 00000000..db602f9e --- /dev/null +++ b/plugins/plugin-md-power/__test__/bilibiliPlugin.spec.ts @@ -0,0 +1,44 @@ +import MarkdownIt from 'markdown-it' +import { describe, expect, it } from 'vitest' +import { bilibiliPlugin } from '../src/node/embed/video/bilibili.js' + +function createMarkdown() { + return MarkdownIt().use((md) => { + md.block.ruler.before('code', 'import_code', () => false) + md.renderer.rules.import_code = () => '' + }).use(bilibiliPlugin) +} + +describe('bilibiliPlugin', () => { + it('should work', () => { + const md = createMarkdown() + const code = `\ +@[bilibili](BV12345) + +@[bilibili](12432 12345) + +@[bilibili](BV12345 12343 45678) + +@[bilibili p1 autoplay time="1"](BV12345) + +@[bilibili p1 autoplay width="100%" height="600px"](BV12345) + +@[bilibili p1 autoplay width="100%" ratio="16:9"](BV12345) +` + expect(md.render(code)).toMatchSnapshot() + }) + + it('should not work', () => { + const md = createMarkdown() + const code = `\ +@[bilibili]() + +@[bilibili]xxx + +@[ bilibili]BV12345 + +@[bilibili](BV12345 +` + expect(md.render(code)).toMatchSnapshot() + }) +}) diff --git a/plugins/plugin-md-power/__test__/caniusePlugin.spec.ts b/plugins/plugin-md-power/__test__/caniusePlugin.spec.ts new file mode 100644 index 00000000..29381195 --- /dev/null +++ b/plugins/plugin-md-power/__test__/caniusePlugin.spec.ts @@ -0,0 +1,73 @@ +import type { CanIUseOptions } from '../src/shared/index.js' +import MarkdownIt from 'markdown-it' +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { caniusePlugin, legacyCaniuse } from '../src/node/embed/caniuse.js' + +beforeEach(() => { + vi.mock('../src/node/utils/nanoid.js', () => ({ + nanoid: vi.fn(() => 'test-id'), + })) +}) + +function createMarkdown(options?: CanIUseOptions) { + return MarkdownIt().use((md) => { + md.block.ruler.before('code', 'import_code', () => false) + md.renderer.rules.import_code = () => '' + }).use(caniusePlugin, options) +} + +describe('caniusePlugin', () => { + it('should work', () => { + const md = createMarkdown() + + expect(md.render('@[caniuse](feature)')).toMatchSnapshot() + expect(md.render('@[caniuse image](feature)')).toMatchSnapshot() + expect(md.render('@[caniuse embed](feature)')).toMatchSnapshot() + expect(md.render('@[caniuse {-2,4}](feature)')).toMatchSnapshot() + expect(md.render(`\ +@[caniuse {-2,4}](feature) +@[caniuse {-2,}](feature) +`)).toMatchSnapshot() + expect(md.render('@[caniuse embed{-2,4}](feature)')).toMatchSnapshot() + }) + + it('should work with options', () => { + const md = createMarkdown({ mode: 'image' }) + + expect(md.render('@[caniuse](feature)')).toMatchSnapshot() + expect(md.render('@[caniuse embed](feature)')).toMatchSnapshot() + expect(md.render('@[caniuse embed{-2,4}](feature)')).toMatchSnapshot() + }) + + it('should not work', () => { + const md = createMarkdown() + + expect(md.render('@[caniuse]()')).toMatchSnapshot() + expect(md.render('@[caniuse]xxx')).toMatchSnapshot() + expect(md.render('@[ caniuse]()')).toMatchSnapshot() + expect(md.render('@[caniuse](xxx')).toMatchSnapshot() + expect(md.render('@[caniuse](')).toMatchSnapshot() + expect(md.render('@[caniuse')).toMatchSnapshot() + expect(md.render('@[caniuse)]()')).toMatchSnapshot() + expect(md.render('@[caniuseee)]()')).toMatchSnapshot() + }) +}) + +describe('legacyCaniuse', () => { + it('should work', () => { + const md = MarkdownIt() + legacyCaniuse(md) + + expect(md.render(':::caniuse feature\n:::')).toMatchSnapshot() + expect(md.render(':::caniuse feature{-2,4}\n:::')).toMatchSnapshot() + expect(md.render(':::caniuse\n:::')).toMatchSnapshot() + }) + + it('should work with unknown mode', () => { + const md = MarkdownIt() + legacyCaniuse(md, { mode: 'unknown' as any }) + + expect(md.render(':::caniuse feature\n:::')).toMatchSnapshot() + expect(md.render(':::caniuse feature{-2,4}\n:::')).toMatchSnapshot() + }) +}) diff --git a/plugins/plugin-md-power/__test__/codeSandboxPlugin.spec.ts b/plugins/plugin-md-power/__test__/codeSandboxPlugin.spec.ts new file mode 100644 index 00000000..975af8f5 --- /dev/null +++ b/plugins/plugin-md-power/__test__/codeSandboxPlugin.spec.ts @@ -0,0 +1,40 @@ +import MarkdownIt from 'markdown-it' +import { describe, expect, it } from 'vitest' +import { codeSandboxPlugin } from '../src/node/embed/code/codeSandbox.js' + +function createMarkdown() { + return MarkdownIt().use((md) => { + md.block.ruler.before('code', 'import_code', () => false) + md.renderer.rules.import_code = () => '' + }).use(codeSandboxPlugin) +} + +describe('codeSandboxPlugin', () => { + it('should work', () => { + const md = createMarkdown() + const code = `\ +@[codesandbox](user/id) + +@[codesandbox embed](user/id) + +@[codesandbox button](user/id) + +@[codesandbox title="xxx" layout="Editor+Preview" width="100%" height="500px" navbar="false" console="false"](user/slash#filepath) +` + + expect(md.render(code)).toMatchSnapshot() + }) + + it('should not work', () => { + const md = createMarkdown() + const code = `\ +@[codesandbox]() + +@[codesandbox]xxx + +@[codesandbox embed]( +` + + expect(md.render(code)).toMatchSnapshot() + }) +}) diff --git a/plugins/plugin-md-power/__test__/codeTabsPlugin.spec.ts b/plugins/plugin-md-power/__test__/codeTabsPlugin.spec.ts new file mode 100644 index 00000000..d05caf54 --- /dev/null +++ b/plugins/plugin-md-power/__test__/codeTabsPlugin.spec.ts @@ -0,0 +1,79 @@ +import type { CodeTabsOptions } from '../src/shared/codeTabs.js' +import MarkdownIt from 'markdown-it' +import { describe, expect, it } from 'vitest' +import { codeTabs } from '../src/node/container/codeTabs.js' + +function createMarkdown(options?: CodeTabsOptions) { + const md = new MarkdownIt() + md.options.highlight = (str, lang) => { + return `
${str}
` + } + md.use(codeTabs, options) + return md +} + +const FENCE = '```' + +describe('codeTabsPlugin', () => { + const code = `\ +::: code-tabs +@tab tab-1 +${FENCE}js +const a = 1 +${FENCE} +@tab tab-2 +${FENCE}js +const b = 2 +${FENCE} +@tab tab-3 +${FENCE}js +const c = 3 +${FENCE} +::: + +::: code-tabs +@tab npm +${FENCE}sh +npm i +${FENCE} +@tab:active pnpm +${FENCE}sh +pnpm i +${FENCE} +@tab yarn +${FENCE}sh +yarn +${FENCE} +::: + +::: code-tabs#pm +@tab a.ts +${FENCE}ts +const a = 1 +${FENCE} +@tab a.js +${FENCE}js +const a = 1 +${FENCE} +::: +` + it('should work with default', () => { + const md = createMarkdown() + expect(md.render(code)).toMatchSnapshot() + }) + + it('should work with no icon', () => { + const md = createMarkdown({ icon: false }) + expect(md.render(code)).toMatchSnapshot() + }) + + it('should work with options: `{ named: false, extensions: false }`', () => { + const md = createMarkdown({ icon: { named: false, extensions: false } }) + expect(md.render(code)).toMatchSnapshot() + }) + + it('should work with options: { named: [npm,pnpm,yarn], extensions: [.js,.ts] }', () => { + const md = createMarkdown({ icon: { named: ['npm', 'pnpm', 'yarn'], extensions: ['.js', '.ts'] } }) + expect(md.render(code)).toMatchSnapshot() + }) +}) diff --git a/plugins/plugin-md-power/__test__/codepenPlugin.spec.ts b/plugins/plugin-md-power/__test__/codepenPlugin.spec.ts new file mode 100644 index 00000000..cf2e4ae3 --- /dev/null +++ b/plugins/plugin-md-power/__test__/codepenPlugin.spec.ts @@ -0,0 +1,38 @@ +import MarkdownIt from 'markdown-it' +import { describe, expect, it } from 'vitest' +import { codepenPlugin } from '../src/node/embed/code/codepen.js' + +function createMarkdown() { + return MarkdownIt().use((md) => { + md.block.ruler.before('code', 'import_code', () => false) + md.renderer.rules.import_code = () => '' + }).use(codepenPlugin) +} + +describe('codepenPlugin', () => { + it('should work', () => { + const md = createMarkdown() + const code = `\ +@[codepen](user/slash) + +@[codepen preview](user/slash) + +@[codepen preview editable title="codepen" width="100%" height="400px" tab="css,result" theme="dark"](user/slash) +` + + expect(md.render(code)).toMatchSnapshot() + }) + + it('should not work', () => { + const md = createMarkdown() + const code = `\ +@[codepen]() + +@[codepen]xxx + +@[codepen preview]( +` + + expect(md.render(code)).toMatchSnapshot() + }) +}) diff --git a/plugins/plugin-md-power/__test__/fileTreePlugin.spec.ts b/plugins/plugin-md-power/__test__/fileTreePlugin.spec.ts new file mode 100644 index 00000000..7ba6a00c --- /dev/null +++ b/plugins/plugin-md-power/__test__/fileTreePlugin.spec.ts @@ -0,0 +1,58 @@ +import type { FileTreeOptions } from '../src/shared/fileTree.js' +import MarkdownIt from 'markdown-it' +import { describe, expect, it } from 'vitest' +import { fileTreePlugin } from '../src/node/container/fileTree.js' + +function createMarkdown(options?: FileTreeOptions) { + return new MarkdownIt().use(fileTreePlugin, options) +} + +describe('fileTreePlugin', () => { + const code = `\ +:::file-tree +- docs + - README.md + - foo.md +- src + - client + - components + - **Navbar.vue** + - index.ts \# comment + - node + - index.ts +- .gitignore +- package.json +::: + +::: file-tree title="files" +- src + - js + - … + - vue/ + - css/ +- README.md +::: + +::: file-tree icon="simple" +- docs +- src + - a.js + - b.ts +- README.md +::: + +::: file-tree +- +- + - +::: + +::: file-tree +::: +` + it('should work with default options', () => { + const md = createMarkdown() + + expect(md.render(code)).toMatchSnapshot() + }) +}) diff --git a/plugins/plugin-md-power/__test__/findIcon.spec.ts b/plugins/plugin-md-power/__test__/findIcon.spec.ts new file mode 100644 index 00000000..3053b7a9 --- /dev/null +++ b/plugins/plugin-md-power/__test__/findIcon.spec.ts @@ -0,0 +1,48 @@ +import { describe, expect, it } from 'vitest' +import { getFileIcon } from '../src/node/fileIcons/index.js' + +describe('getFileIcon(filename, type)', () => { + it('should find icon with default', () => { + expect(getFileIcon('a.js')).toBe('vscode-icons:file-type-js') + expect(getFileIcon('a.cjs')).toBe('vscode-icons:file-type-js') + expect(getFileIcon('a.mjs')).toBe('vscode-icons:file-type-js') + expect(getFileIcon('a.jsx')).toBe('vscode-icons:file-type-reactjs') + expect(getFileIcon('a.ts')).toBe('vscode-icons:file-type-typescript') + expect(getFileIcon('a.d.ts')).toBe('vscode-icons:file-type-typescript') + expect(getFileIcon('a.cjs.map')).toBe('vscode-icons:file-type-jsmap') + expect(getFileIcon('a.mjs.map')).toBe('vscode-icons:file-type-jsmap') + + expect(getFileIcon('vue')).toBe('vscode-icons:file-type-vue') + expect(getFileIcon('Svelte')).toBe('vscode-icons:file-type-svelte') + }) + + it('should find icon with folder', () => { + expect(getFileIcon('xxx', 'folder')).toBe('vscode-icons:default-folder') + expect(getFileIcon('src', 'folder')).toBe('vscode-icons:folder-type-src') + expect(getFileIcon('src/client', 'folder')).toBe('vscode-icons:folder-type-client') + }) + + it('should find icon with named file', () => { + expect(getFileIcon('webpack.config.js')).toBe('vscode-icons:file-type-webpack') + expect(getFileIcon('vite.config.mjs')).toBe('vscode-icons:file-type-vite') + expect(getFileIcon('test/vitest.config.js')).toBe('vscode-icons:file-type-js') + }) + + it('should find icon with extensions', () => { + expect(getFileIcon('a.cpp')).toBe('vscode-icons:file-type-cpp') + expect(getFileIcon('a.spec.mjs')).toBe('vscode-icons:file-type-light-testjs') + }) + + it('should find icon with partials', () => { + expect(getFileIcon('LICENSE')).toBe('vscode-icons:file-type-license') + expect(getFileIcon('Gemfile')).toBe('vscode-icons:file-type-ruby') + }) + + it('should return default icon when not find', () => { + expect(getFileIcon('a.abcxxx')).toBe('vscode-icons:default-file') + expect(getFileIcon('a.abcxxx.tbnmmb.z')).toBe('vscode-icons:default-file') + expect(getFileIcon('abc.', 'file')).toBe('vscode-icons:default-file') + expect(getFileIcon('abc.', 'folder')).toBe('vscode-icons:default-folder') + expect(getFileIcon('')).toBe('vscode-icons:default-file') + }) +}) diff --git a/plugins/plugin-md-power/__test__/iconsPlugin.spec.ts b/plugins/plugin-md-power/__test__/iconsPlugin.spec.ts new file mode 100644 index 00000000..eddb32a6 --- /dev/null +++ b/plugins/plugin-md-power/__test__/iconsPlugin.spec.ts @@ -0,0 +1,48 @@ +import MarkdownIt from 'markdown-it' +import { describe, expect, it } from 'vitest' +import { iconsPlugin } from '../src/node/inline/icons.js' + +describe('iconsPlugin', () => { + it('should work', () => { + const md = MarkdownIt().use(iconsPlugin) + + expect(md.render(':[mdi:11]:')).toMatchSnapshot() + expect(md.render('**strong** :[mdi:11]: :[mdi:11]:')).toMatchSnapshot() + expect(md.render('**strong**\n:[mdi:11]:\n :[mdi:11]:')).toMatchSnapshot() + }) + + it('should work with options', () => { + const md = MarkdownIt().use(iconsPlugin, { size: '1.25em', color: '#ccc' }) + + expect(md.render(':[mdi:11]:')).toMatchSnapshot() + expect(md.render('**strong** :[mdi:11]: :[mdi:11]:')).toMatchSnapshot() + }) + + it('should work with single icon options', () => { + const md = MarkdownIt().use(iconsPlugin) + + expect(md.render(':[mdi:11 36px]:')).toMatchSnapshot() + expect(md.render(':[mdi:11 32px/#eee]:')).toMatchSnapshot() + expect(md.render(':[mdi:11 /#eee]:')).toMatchSnapshot() + expect(md.render(':[mdi:11 32px/]:')).toMatchSnapshot() + expect(md.render(':[mdi:11 /]:')).toMatchSnapshot() + + const md2 = MarkdownIt().use(iconsPlugin, { size: '1.25em', color: '#ccc' }) + expect(md2.render(':[mdi:11]:')).toMatchSnapshot() + expect(md2.render(':[mdi:11 36px]:')).toMatchSnapshot() + expect(md2.render(':[mdi:11 32px/#eee]:')).toMatchSnapshot() + expect(md2.render(':[mdi:11 /#eee]:')).toMatchSnapshot() + expect(md2.render(':[mdi:11 32px/]:')).toMatchSnapshot() + expect(md2.render(':[mdi:11 /]:')).toMatchSnapshot() + }) + + it('should not work with invalid icon', () => { + const md = MarkdownIt().use(iconsPlugin) + + expect(md.render(':[ mdi:11 ]:')).toMatchSnapshot() + expect(md.render(':[]:')).toMatchSnapshot() + expect(md.render(':[]&')).toMatchSnapshot() + expect(md.render(':[:[')).toMatchSnapshot() + expect(md.render(':[mdi:11')).toMatchSnapshot() + }) +}) diff --git a/plugins/plugin-md-power/__test__/jsfiddlePlugin.spec.ts b/plugins/plugin-md-power/__test__/jsfiddlePlugin.spec.ts new file mode 100644 index 00000000..9676c5c4 --- /dev/null +++ b/plugins/plugin-md-power/__test__/jsfiddlePlugin.spec.ts @@ -0,0 +1,40 @@ +import MarkdownIt from 'markdown-it' +import { describe, expect, it } from 'vitest' +import { jsfiddlePlugin } from '../src/node/embed/code/jsfiddle.js' + +function createMarkdown() { + return MarkdownIt().use((md) => { + md.block.ruler.before('code', 'import_code', () => false) + md.renderer.rules.import_code = () => '' + }).use(jsfiddlePlugin) +} + +describe('codeSandboxPlugin', () => { + it('should work', () => { + const md = createMarkdown() + const code = `\ +@[jsfiddle](user/id) + +@[jsfiddle](user/id) + +@[jsfiddle theme="light"](user/id) + +@[jsfiddle title="xxx" width="100%" height="500px" theme="dark" tab="js,css,html,result"](user/id) +` + + expect(md.render(code)).toMatchSnapshot() + }) + + it('should not work', () => { + const md = createMarkdown() + const code = `\ +@[jsfiddle]() + +@[jsfiddle]xxx + +@[jsfiddle]( +` + + expect(md.render(code)).toMatchSnapshot() + }) +}) diff --git a/plugins/plugin-md-power/__test__/npmToPlugin.spec.ts b/plugins/plugin-md-power/__test__/npmToPlugin.spec.ts new file mode 100644 index 00000000..9d64b42b --- /dev/null +++ b/plugins/plugin-md-power/__test__/npmToPlugin.spec.ts @@ -0,0 +1,131 @@ +import type { NpmToOptions } from '../src/shared/npmTo.js' +import MarkdownIt from 'markdown-it' +import { describe, expect, it } from 'vitest' +import { codeTabs } from '../src/node/container/codeTabs.js' +import { npmToPlugins, parseLine } from '../src/node/container/npmTo.js' + +function createMarkdown(options?: NpmToOptions) { + return new MarkdownIt({ + highlight: (str, lang) => `
${str}
`, + }).use(codeTabs).use(npmToPlugins, options) +} + +const FENCE = '```' + +describe('npmToPlugin', () => { + const code = `\ +::: npm-to +${FENCE}sh +${FENCE} +::: + +::: npm-to +${FENCE}sh +npm install +${FENCE} +::: + +::: npm-to +${FENCE}shell +npm install +${FENCE} +::: + +::: npm-to +${FENCE}bash +npm install +${FENCE} +::: + +::: npm-to +${FENCE}sh +cross-env NODE_ENV=production npm run docs +${FENCE} +::: + +::: npm-to +${FENCE}sh +npm i -D package1 package2 +npm i --save-peer package3 +npm run docs +${FENCE} +::: + +::: npm-to +${FENCE}sh +npm install && npm run docs +mkdir foo +${FENCE} +::: + +::: npm-to +${FENCE}sh +npm run docs -- --clean-cache --clean-temp + +${FENCE} +::: + +::: npm-to tabs="," +${FENCE}sh +npm create vuepress-theme-plume@latest +${FENCE} +::: + +::: npm-to tabs="npm,pnpm,yarn,bun,deno" +${FENCE}sh +npx vp-update +${FENCE} +::: + +::: npm-to +${FENCE}sh +mkdir foo +${FENCE} +::: + +::: npm-to +anything +${FENCE}sh +${FENCE} +::: +` + it('should work with default options', () => { + const md = createMarkdown() + + expect(md.render(code)).toMatchSnapshot() + }) + + it('should work width options: { tabs: [npm, yarn, pnpm] }', () => { + const md = createMarkdown({ tabs: ['npm', 'yarn', 'pnpm'] }) + + expect(md.render(code)).toMatchSnapshot() + }) + + it('should work width options: [npm, yarn, pnpm]', () => { + const md = createMarkdown(['npm', 'yarn', 'pnpm']) + + expect(md.render(code)).toMatchSnapshot() + }) +}) + +describe('parseLine', () => { + it('should work', () => { + expect(parseLine('npm install')).toMatchObject({ env: '', cli: 'npm install', cmd: '' }) + expect(parseLine('npx vp-update')).toMatchObject({ env: '', cli: 'npx', cmd: 'vp-update' }) + expect(parseLine('npx vp-update --foo')).toMatchObject({ env: '', cli: 'npx', cmd: 'vp-update', scriptArgs: '--foo' }) + expect(parseLine('npm run docs')).toMatchObject({ env: '', cli: 'npm run', cmd: 'docs' }) + expect(parseLine('npm i -D package1 -- --foo')) + .toMatchObject({ env: '', cli: 'npm i', cmd: 'package1', args: '-D', scriptArgs: '--foo' }) + expect(parseLine('npm install -y')).toMatchObject({ env: '', cli: 'npm install', cmd: '', args: '-y' }) + expect(parseLine('npm create vuepress-theme-plume my-blog')).toMatchObject({ env: '', cli: 'npm create', cmd: 'vuepress-theme-plume my-blog' }) + expect(parseLine('npm create "vuepress-theme-plume my-blog"')).toMatchObject({ env: '', cli: 'npm create', cmd: '"vuepress-theme-plume my-blog"' }) + expect(parseLine('npm create vuepress-theme-plume my-blog --foo -B')).toMatchObject({ env: '', cli: 'npm create', cmd: 'vuepress-theme-plume my-blog', args: '--foo -B' }) + + expect(parseLine('npm run -w="my-workspace" docs')).toMatchObject({ env: '', cli: 'npm run', cmd: 'docs', args: '-w="my-workspace"' }) + }) + + it('should not match', () => { + expect(parseLine('mkdir foo')).toBe(false) + expect(parseLine('')).toBe(false) + }) +}) diff --git a/plugins/plugin-md-power/__test__/parseRect.spec.ts b/plugins/plugin-md-power/__test__/parseRect.spec.ts new file mode 100644 index 00000000..5399005a --- /dev/null +++ b/plugins/plugin-md-power/__test__/parseRect.spec.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'vitest' +import { parseRect } from '../src/node/utils/parseRect.js' + +describe('parseRect(str)', () => { + it('should parse rect', () => { + expect(parseRect('')).toBe('') + expect(parseRect('1')).toBe('1px') + expect(parseRect('1px')).toBe('1px') + expect(parseRect('1%')).toBe('1%') + expect(parseRect('1em')).toBe('1em') + expect(parseRect('1cm')).toBe('1cm') + }) + + it('should parse rect with unit', () => { + expect(parseRect('1', 'px')).toBe('1px') + expect(parseRect('1px', 'px')).toBe('1px') + expect(parseRect('1%', 'px')).toBe('1%') + expect(parseRect('1em', 'px')).toBe('1em') + }) +}) diff --git a/plugins/plugin-md-power/__test__/pdfPlugin.spec.ts b/plugins/plugin-md-power/__test__/pdfPlugin.spec.ts new file mode 100644 index 00000000..e759720d --- /dev/null +++ b/plugins/plugin-md-power/__test__/pdfPlugin.spec.ts @@ -0,0 +1,47 @@ +import MarkdownIt from 'markdown-it' +import { describe, expect, it } from 'vitest' +import { pdfPlugin } from '../src/node/embed/pdf.js' + +function createMarkdown() { + return MarkdownIt().use((md) => { + md.block.ruler.before('code', 'import_code', () => false) + md.renderer.rules.import_code = () => '' + }).use(pdfPlugin) +} + +describe('pdfPlugin', () => { + it('should work', () => { + const md = createMarkdown() + const code = `\ +@[pdf](foo.pdf) + +@[pdf no-toolbar](foo.pdf) + +@[pdf 2](foo.pdf) + +@[pdf 2 no-toolbar](foo.pdf) + +@[pdf 2 no-toolbar width="100%" height="600px" zoom="1"](foo.pdf) + +@[pdf 2 no-toolbar width="100%" zoom="1" ratio="1:1"](foo.pdf) +` + + expect(md.render('@[pdf](foo.pdf)')).toMatchSnapshot() + expect(md.render(code)).toMatchSnapshot() + }) + + it('should not work', () => { + const md = createMarkdown() + const code = `\ +@[pdf]() + +@[pdf]xxx + +@[ pdf]() + +@[pdf] +` + + expect(md.render(code)).toMatchSnapshot() + }) +}) diff --git a/plugins/plugin-md-power/__test__/plotPlugin.spec.ts b/plugins/plugin-md-power/__test__/plotPlugin.spec.ts new file mode 100644 index 00000000..3131a6cb --- /dev/null +++ b/plugins/plugin-md-power/__test__/plotPlugin.spec.ts @@ -0,0 +1,22 @@ +import MarkdownIt from 'markdown-it' +import { describe, expect, it } from 'vitest' +import { plotPlugin } from '../src/node/inline/plot.js' + +describe('plotPlugin', () => { + it('should work', () => { + const md = MarkdownIt().use(plotPlugin) + + expect(md.render('!!plot!!')).toMatchSnapshot() + expect(md.render('hidden: !!plot!! **strong**')).toMatchSnapshot() + expect(md.render('hidden: \n!!plot!! \n!!plot!!')).toMatchSnapshot() + }) + + it('should not work with invalid tag', () => { + const md = MarkdownIt().use(plotPlugin) + + expect(md.render('!!!!')).toMatchSnapshot() + expect(md.render('!!plot!')).toMatchSnapshot() + expect(md.render('!!!')).toMatchSnapshot() + expect(md.render('!! plot !!')).toMatchSnapshot() + }) +}) diff --git a/plugins/plugin-md-power/__test__/resolveAttrs.spec.ts b/plugins/plugin-md-power/__test__/resolveAttrs.spec.ts new file mode 100644 index 00000000..83ff8648 --- /dev/null +++ b/plugins/plugin-md-power/__test__/resolveAttrs.spec.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from 'vitest' +import { resolveAttrs } from '../src/node/utils/resolveAttrs.js' + +describe('resolveAttrs(info)', () => { + it('should resolve attrs', () => { + expect(resolveAttrs('')).toMatchObject({ rawAttrs: '', attrs: {} }) + + expect(resolveAttrs('a="1"')).toMatchObject({ + rawAttrs: 'a="1"', + attrs: { a: '1' }, + }) + + expect(resolveAttrs('a="1" b="2"')).toMatchObject({ + rawAttrs: 'a="1" b="2"', + attrs: { a: '1', b: '2' }, + }) + + expect(resolveAttrs('a="1" b="2" c')).toMatchObject({ + rawAttrs: 'a="1" b="2" c', + attrs: { a: '1', b: '2', c: true }, + }) + + expect(resolveAttrs('a b="true" c="false"')).toMatchObject({ + rawAttrs: 'a b="true" c="false"', + attrs: { a: true, b: true, c: false }, + }) + }) + + it('should resolve attrs with include `-`', () => { + expect(resolveAttrs('foo-bar="1" fizz-buzz')).toMatchObject({ + rawAttrs: 'foo-bar="1" fizz-buzz', + attrs: { 'fooBar': '1', 'fizzBuzz': true, 'foo-bar': '1', 'fizz-buzz': true }, + }) + }) +}) diff --git a/plugins/plugin-md-power/__test__/timeToSeconds.spec.ts b/plugins/plugin-md-power/__test__/timeToSeconds.spec.ts new file mode 100644 index 00000000..de06c58d --- /dev/null +++ b/plugins/plugin-md-power/__test__/timeToSeconds.spec.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from 'vitest' +import { timeToSeconds } from '../src/node/utils/timeToSeconds.js' + +describe('timeToSeconds(timeLike)', () => { + it('should return seconds', () => { + expect(timeToSeconds('')).toBe(0) + expect(timeToSeconds('1')).toBe(1) + expect(timeToSeconds('69')).toBe(69) + }) + + it('should return seconds with h:m:s', () => { + expect(timeToSeconds('1:2')).toBe(62) + expect(timeToSeconds('1:2:3')).toBe(3723) + expect(timeToSeconds('1:2:3.4')).toBe(3723.4) + expect(timeToSeconds('1:2:')).toBe(3720) + expect(timeToSeconds(':2:3')).toBe(123) + expect(timeToSeconds('::3')).toBe(3) + }) + + it('show return seconds with include incorrect char', () => { + expect(timeToSeconds('1:a:b')).toBe(3600) + expect(timeToSeconds('1:2:a')).toBe(3720) + expect(timeToSeconds('a:b')).toBe(0) + expect(timeToSeconds('a : b : c')).toBe(0) + }) +}) diff --git a/plugins/plugin-md-power/__test__/youtubePlugin.spec.ts b/plugins/plugin-md-power/__test__/youtubePlugin.spec.ts new file mode 100644 index 00000000..f887c2fe --- /dev/null +++ b/plugins/plugin-md-power/__test__/youtubePlugin.spec.ts @@ -0,0 +1,44 @@ +import MarkdownIt from 'markdown-it' +import { describe, expect, it } from 'vitest' +import { youtubePlugin } from '../src/node/embed/video/youtube.js' + +function createMarkdown() { + return MarkdownIt().use((md) => { + md.block.ruler.before('code', 'import_code', () => false) + md.renderer.rules.import_code = () => '' + }).use(youtubePlugin) +} + +describe('youtubePlugin', () => { + it('should work', () => { + const md = createMarkdown() + const code = `\ +@[youtube](123456) + +@[youtube loop autoplay title="test"](123456) + +@[youtube autoplay start="40" end="1:20"](123456) + +@[youtube width="100%" height="600px"](123456) + +@[youtube width="100%" ratio="16:9"](123456) +` + + expect(md.render(code)).toMatchSnapshot() + }) + + it('should not work', () => { + const md = createMarkdown() + const code = `\ +@[youtube]() + +@[youtube]xxx + +@[ youtube]123456 + +@[ youtube](123456) +` + + expect(md.render(code)).toMatchSnapshot() + }) +}) diff --git a/plugins/plugin-md-power/src/node/container/codeTabs.ts b/plugins/plugin-md-power/src/node/container/codeTabs.ts index 9e52a45f..1153f54d 100644 --- a/plugins/plugin-md-power/src/node/container/codeTabs.ts +++ b/plugins/plugin-md-power/src/node/container/codeTabs.ts @@ -6,7 +6,7 @@ import { definitions, getFileIconName, getFileIconTypeFromExtension } from '../f import { stringifyProp } from '../utils/stringifyProp.js' export const codeTabs: PluginWithOptions = (md, options: CodeTabsOptions = {}) => { - const getIcon = (filename: string): string | undefined => { + const getIcon = (filename: string): string | void => { if (options.icon === false) return undefined const { named, extensions } = isPlainObject(options.icon) ? options.icon : {} @@ -54,20 +54,18 @@ export const codeTabs: PluginWithOptions = (md, options: CodeTa // Hide all elements excerpt the first fence for (let i = tokenIndex; i < tokens.length; i++) { - const { block, type } = tokens[i] + const { type } = tokens[i] - if (block) { - if (type === 'code-tabs_tab_close') - break + if (type === 'code-tabs_tab_close') + break - if ((type === 'fence' || type === 'import_code') && !foundFence) { - foundFence = true - continue - } - - tokens[i].type = 'code_tab_empty' - tokens[i].hidden = true + if ((type === 'fence' || type === 'import_code') && !foundFence) { + foundFence = true + continue } + + tokens[i].type = 'code_tab_empty' + tokens[i].hidden = true } return `