diff --git a/.eslintignore b/.eslintignore index b9a9017c5..846f112d6 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,9 +3,8 @@ packages/docsify-server-renderer/build.js node_modules build server.js -cypress lib themes build docs/ -**/*.md \ No newline at end of file +**/*.md diff --git a/.eslintrc.js b/.eslintrc.js index d08568536..b15f54fe8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,7 +6,6 @@ module.exports = { ecmaVersion: 2019, }, env: { - jest: true, browser: true, node: true, es6: true, diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index bb31bd41f..2d5b3e545 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -14,6 +14,7 @@ - [ ] Refactor - [ ] Docs - [ ] Build-related changes +- [ ] Repo settings - [ ] Other, please describe: If changing the UI of default theme, please provide the **before/after** screenshot: @@ -44,11 +45,3 @@ If adding a **new feature**, the PR's description includes: - [ ] Related tests have been updated To avoid wasting your time, it's best to open a **feature request issue** first and wait for approval before working on it. - - -**Other information:** - ---- - -* [ ] DO NOT include files inside `lib` directory. - diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index 3b2c8b180..000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,20 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 60 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 7 -# Issues with these labels will never be considered stale -exemptLabels: - - pinned - - security - - On hold - - enhancement - - bug -# Label to use when marking an issue as stale -staleLabel: wontfix -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml deleted file mode 100644 index 09fd229fa..000000000 --- a/.github/workflows/e2e.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Testing the e2e test suites - -on: - push: - branches: - - master - - develop - pull_request: - branches: - - master - - develop - -jobs: - build: - runs-on: ubuntu-16.04 - strategy: - matrix: - node-version: [10.x, 12.x, 13.x] - - steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: bootstrap - run: npm run bootstrap - - name: Build - run: npm run build - - name: end to end - run: npm run test:e2e diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8e40422e8..a68cb5ef7 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,31 +1,30 @@ -name: Linting Checks +name: Lint -on: +on: push: - branches: - - master - - develop + branches: + - master + - develop pull_request: - branches: - - master - - develop + branches: + - master + - develop jobs: build: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - node-version: [10.x, 12.x, 13.x] + node-version: [12.x, 14.x] steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: bootstrap - run: npm run bootstrap - - name: Build - run: npm run build - - name: Linting - run: npm run lint + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Install + run: npm i --ignore-scripts + - name: Lint + run: npm run lint diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..296b8d7ed --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,42 @@ +name: Build & Test + +on: + push: + branches: + - master + - develop + pull_request: + branches: + - master + - develop + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + node-version: [12.x, 14.x] + os: ['macos-latest', 'ubuntu-latest', 'windows-latest'] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: bootstrap + run: npm run bootstrap + - name: unit tests + run: npm run test:unit -- -ci --runInBand + - name: integration tests + run: npm run test:integration -- -ci --runInBand + - uses: microsoft/playwright-github-action@v1.3.0 + - name: e2e tests + run: npm run test:e2e -- --ci --runInBand + - name: Upload artifacts (diff output) + uses: actions/upload-artifact@v2 + if: failure() + with: + name: ${{ matrix.os }}-${{ matrix.node-version }}-diff-output + path: ${{ github.workspace }}/test/**/__diff_output__/* diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml deleted file mode 100644 index 45c001f7a..000000000 --- a/.github/workflows/unit.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Unit tests Suite - -on: - push: - branches: - - master - - develop - pull_request: - branches: - - master - - develop - -jobs: - build: - runs-on: ubuntu-16.04 - strategy: - matrix: - node-version: [10.x, 12.x, 13.x] - - steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: bootstrap - run: npm run bootstrap - - name: Build - run: npm run build - - name: Unit tests - run: npm run test diff --git a/.gitignore b/.gitignore index e9803a96f..6c1c491a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,10 @@ *.log .DS_Store .idea +__diff_output__ +lib/ node_modules themes/ -lib/ -cypress/integration/examples -cypress/fixtures/docs # exceptions -!.gitkeep \ No newline at end of file +!.gitkeep diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..fb00f67b6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,73 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Run tests", + "runtimeExecutable": "npm", + "runtimeArgs": ["run-script", "test"], + "console": "integratedTerminal" + }, + { + "type": "node", + "request": "launch", + "name": "Run current test file", + "runtimeExecutable": "npm", + "runtimeArgs": ["run-script", "test"], + "args": ["--", "-i", "${relativeFile}", "--testPathIgnorePatterns"], + "console": "integratedTerminal" + }, + { + "type": "node", + "request": "launch", + "name": "Run selected test name", + "runtimeExecutable": "npm", + "runtimeArgs": ["run-script", "test"], + "args": [ + "--", + "-i", + "${relativeFile}", + "-t", + "${selectedText}", + "--testPathIgnorePatterns" + ], + "console": "integratedTerminal" + }, + { + "type": "node", + "request": "launch", + "name": "Update current test file snapshot(s)", + "runtimeExecutable": "npm", + "runtimeArgs": ["run-script", "test"], + "args": [ + "--", + "-i", + "${relativeFile}", + "--updateSnapshot", + "--testPathIgnorePatterns" + ], + "console": "integratedTerminal" + }, + { + "type": "node", + "request": "launch", + "name": "Update selected test name snapshot(s)", + "runtimeExecutable": "npm", + "runtimeArgs": ["run-script", "test"], + "args": [ + "--", + "-i", + "${relativeFile}", + "-t", + "${selectedText}", + "--updateSnapshot", + "--testPathIgnorePatterns" + ], + "console": "integratedTerminal" + } + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index b53241891..14afb19af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,70 @@ +## [4.11.6](https://github.com/docsifyjs/docsify/compare/v4.11.5...v4.11.6) (2020-08-22) + + +### Bug Fixes + +* Add patch for {docsify-ignore} and {docsify-ignore-all} ([ce31607](https://github.com/docsifyjs/docsify/commit/ce316075e033afdbeb43ce01e284a29fe1870e38)) + + + +## [4.11.5](https://github.com/docsifyjs/docsify/compare/v4.11.4...v4.11.5) (2020-08-21) + + +### Bug Fixes + +* Russian language link error ([#1270](https://github.com/docsifyjs/docsify/issues/1270)) ([2a52460](https://github.com/docsifyjs/docsify/commit/2a52460a59448abaf681046fbc5dca642285ae1f)) +* {docsify-updated} in the sample code is parsed into time ([#1321](https://github.com/docsifyjs/docsify/issues/1321)) ([2048610](https://github.com/docsifyjs/docsify/commit/2048610aacd4e3c6a592f4247834a726c7ca33fb)) +* Add error handling for missing dependencies (fixes [#1210](https://github.com/docsifyjs/docsify/issues/1210)) ([#1232](https://github.com/docsifyjs/docsify/issues/1232)) ([3673001](https://github.com/docsifyjs/docsify/commit/3673001a24cb24c57454f9bc7619de49d2c3a044)) +* after setting the background image, the button is obscured ([#1234](https://github.com/docsifyjs/docsify/issues/1234)) ([34d918f](https://github.com/docsifyjs/docsify/commit/34d918f9973bdb8e893248853e3ef7e803d4c253)) +* convert {docsify-ignore} and {docsify-ignore-all} to HTML comments ([#1318](https://github.com/docsifyjs/docsify/issues/1318)) ([90d283d](https://github.com/docsifyjs/docsify/commit/90d283d340502456a5d8495df596bb4a02ceb39b)) +* fallback page should use path not file location ([#1301](https://github.com/docsifyjs/docsify/issues/1301)) ([2bceabc](https://github.com/docsifyjs/docsify/commit/2bceabcb8e623570540493e2f1d956adf45c99e7)) +* Fix search error when exist translations documents ([#1300](https://github.com/docsifyjs/docsify/issues/1300)) ([b869019](https://github.com/docsifyjs/docsify/commit/b8690199006366e86084e9e018def7b9b8f46512)) +* gitignore was ignoring folders in src, so VS Code search results or file fuzzy finder were not working, etc ([d4c9247](https://github.com/docsifyjs/docsify/commit/d4c9247b87c0a2701683ed1a17383cfb451cf609)) +* packages/docsify-server-renderer/package.json & packages/docsify-server-renderer/package-lock.json to reduce vulnerabilities ([#1250](https://github.com/docsifyjs/docsify/issues/1250)) ([d439bac](https://github.com/docsifyjs/docsify/commit/d439bac93f479d0480799880538fc3104e54c907)) +* search can not search the table header ([#1256](https://github.com/docsifyjs/docsify/issues/1256)) ([3f03e78](https://github.com/docsifyjs/docsify/commit/3f03e78418993d8e9a4f5062e10dc79c3753389e)) +* Search plugin: matched text is replaced with search text ([#1298](https://github.com/docsifyjs/docsify/issues/1298)) ([78775b6](https://github.com/docsifyjs/docsify/commit/78775b6ee73102cc5ac71c0ee2b392c5f4f6f4f8)) +* the uncaught typeerror when el is null ([#1308](https://github.com/docsifyjs/docsify/issues/1308)) ([952f4c9](https://github.com/docsifyjs/docsify/commit/952f4c921b7a6a558c500ca6b105582d39ad36a2)) +* Updated docs with instructions for installing specific version (fixes [#780](https://github.com/docsifyjs/docsify/issues/780)) ([#1225](https://github.com/docsifyjs/docsify/issues/1225)) ([b90c948](https://github.com/docsifyjs/docsify/commit/b90c948090e89fa778279c95060dbd7668285658)) +* upgrade medium-zoom from 1.0.5 to 1.0.6 ([3beaa66](https://github.com/docsifyjs/docsify/commit/3beaa6666b78518f1ffaa37f6942f3cb08fef896)) +* upgrade tinydate from 1.2.0 to 1.3.0 ([#1341](https://github.com/docsifyjs/docsify/issues/1341)) ([59d090f](https://github.com/docsifyjs/docsify/commit/59d090fe9096bc03e259c166634bb75bb2623f85)) + + +### Features + +* **search:** add pathNamespaces option ([d179dde](https://github.com/docsifyjs/docsify/commit/d179dde1c71acdcbe66cb762377b123926c55bf2)) +* Add title to sidebar links ([#1286](https://github.com/docsifyjs/docsify/issues/1286)) ([667496b](https://github.com/docsifyjs/docsify/commit/667496b85d99b168255f58e60a6bfe902cc6ee03)) + + + +## [4.11.4](https://github.com/docsifyjs/docsify/compare/v4.11.3...v4.11.4) (2020-06-18) + + +### Bug Fixes + +* consistent location of search result ([e9dd2de](https://github.com/docsifyjs/docsify/commit/e9dd2de384b81619aae2bcbf92f52721cb76a177)) +* cover overlapping sidebar by removing z-index ([0bf03f5](https://github.com/docsifyjs/docsify/commit/0bf03f58103037d100b1635cf3989c8d3672b4ba)) +* cross-origin url cannot be redirected when "externalLinkTarget" is set to "_self" and "routerMode" is set to "history". ([#1062](https://github.com/docsifyjs/docsify/issues/1062)) ([fd2cec6](https://github.com/docsifyjs/docsify/commit/fd2cec6bd66c46d6957811fefae4c615c3052a4f)), closes [#1046](https://github.com/docsifyjs/docsify/issues/1046) [#1046](https://github.com/docsifyjs/docsify/issues/1046) [#1046](https://github.com/docsifyjs/docsify/issues/1046) +* default html img resize if no height included ([#1065](https://github.com/docsifyjs/docsify/issues/1065)) ([9ff4d06](https://github.com/docsifyjs/docsify/commit/9ff4d0677304bc190e7bd9e89bbbdc64895197fa)) +* fixed target and rel issue (fixes [#1183](https://github.com/docsifyjs/docsify/issues/1183)) ([3d662a5](https://github.com/docsifyjs/docsify/commit/3d662a5bf71bbfef077cfbc478df241d794f55a0)) +* Inconsistent search and body rendering ([dcb0aae](https://github.com/docsifyjs/docsify/commit/dcb0aaea99efbd68175f1d1aeb5076b6dde9801e)) +* rendering cover width bug ([717991c](https://github.com/docsifyjs/docsify/commit/717991c90cf709f4da91fe32610129de6529266b)) +* search does not find the contents of the table ([#1198](https://github.com/docsifyjs/docsify/issues/1198)) ([31010e4](https://github.com/docsifyjs/docsify/commit/31010e4979b3d3ab4bd247a09c4ac5fd1405eaa8)) +* The search error after setting the ID in the title ([#1159](https://github.com/docsifyjs/docsify/issues/1159)) ([6e554f8](https://github.com/docsifyjs/docsify/commit/6e554f8ebd3d4a2c5c7e4f66cff3dfe2b6aa1e31)) +* upgrade docsify from 4.10.2 to 4.11.2 ([60b7f89](https://github.com/docsifyjs/docsify/commit/60b7f89b373b0d48ec8406a51eddeaed8126696d)) + + +### Features + +* added html sanitizer for remote rendering ([#1128](https://github.com/docsifyjs/docsify/issues/1128)) ([714ef29](https://github.com/docsifyjs/docsify/commit/714ef29afe779a6db5c4761ebaacdfc70ee2d8dd)) +* update src/core/index.js to export all global APIs, deprecate old globals in favor of a single global DOCSIFY, and add tests for this ([7e002bf](https://github.com/docsifyjs/docsify/commit/7e002bf939d7837843908417b5445b4f8d36c1cd)) + + +### Reverts + +* Revert "Updated docs site dark and light mode with switch and redesigned search bar using docsify-darklight-theme" (#1207) ([26cb940](https://github.com/docsifyjs/docsify/commit/26cb940b51d34ee584b8425012a336f38a4abd76)), closes [#1207](https://github.com/docsifyjs/docsify/issues/1207) [#1182](https://github.com/docsifyjs/docsify/issues/1182) + + + ## [4.11.3](https://github.com/docsifyjs/docsify/compare/v4.11.2...v4.11.3) (2020-03-24) @@ -28,8 +95,8 @@ * emojis in titles not working correctly and update ([#1016](https://github.com/docsifyjs/docsify/issues/1016)) ([b3d9b96](https://github.com/docsifyjs/docsify/commit/b3d9b966dfbb6f456c2c457da1d2a366e85d9190)) * searching table content ([6184e50](https://github.com/docsifyjs/docsify/commit/6184e502629932ca71fdd0a1b10150d118f5a7c8)) * stage modified files as part of pre-commit hook ([#985](https://github.com/docsifyjs/docsify/issues/985)) ([5b77b0f](https://github.com/docsifyjs/docsify/commit/5b77b0f628f056b7ebb6d0b617561d19964516a2)) -* config initialization and coercion ([#861](https://github.com/docsifyjs/docsify/pull/861)) -* strip indent when embedding code fragment ([#996](https://github.com/docsifyjs/docsify/pull/996)) +* config initialization and coercion ([#861](https://github.com/docsifyjs/docsify/pull/861)) +* strip indent when embedding code fragment ([#996](https://github.com/docsifyjs/docsify/pull/996)) * Ensure autoHeader dom result is similar to parsed H1 ([#811](https://github.com/docsifyjs/docsify/pull/811)) * upgrade docsify from 4.9.4 to 4.10.2 ([#1054](https://github.com/docsifyjs/docsify/issues/1054)) ([78290b2](https://github.com/docsifyjs/docsify/commit/78290b21038a3ae09c4c7438bd89b14ca4c02805)) * upgrade medium-zoom from 1.0.4 to 1.0.5 ([39ebd73](https://github.com/docsifyjs/docsify/commit/39ebd73021290439180878cae32e663b9e60e214)) @@ -48,7 +115,7 @@ ### Docs -* update docs for the `name` config option ([#992](https://github.com/docsifyjs/docsify/pull/992)) +* update docs for the `name` config option ([#992](https://github.com/docsifyjs/docsify/pull/992)) * about cache ([#854](https://github.com/docsifyjs/docsify/pull/854)) * removed FOSSA badge * documented `__colon__` tip ([#1025](https://github.com/docsifyjs/docsify/pull/1025)) @@ -56,21 +123,21 @@ ### Chore * Migrate relative links to absolute in embedded markdown ([#867](https://github.com/docsifyjs/docsify/pull/867)) -* smarter scroll behavior ([#744](https://github.com/docsifyjs/docsify/pull/744)) +* smarter scroll behavior ([#744](https://github.com/docsifyjs/docsify/pull/744)) * improve basic layout style ([#884](https://github.com/docsifyjs/docsify/pull/884)) -* There are currently {three=>four} themes available. ([#892](https://github.com/docsifyjs/docsify/pull/892)) -* Added a redirect for images to show up in Amplify ([#918](https://github.com/docsifyjs/docsify/pull/918)) +* There are currently {three=>four} themes available. ([#892](https://github.com/docsifyjs/docsify/pull/892)) +* Added a redirect for images to show up in Amplify ([#918](https://github.com/docsifyjs/docsify/pull/918)) * removed the escaping of the name of sidebar ([#991](https://github.com/docsifyjs/docsify/pull/991)) -* Eslint fixes for v4x ([#989](https://github.com/docsifyjs/docsify/pull/989)) -* added github Actions for CI ([#1000](https://github.com/docsifyjs/docsify/pull/1000)) +* Eslint fixes for v4x ([#989](https://github.com/docsifyjs/docsify/pull/989)) +* added github Actions for CI ([#1000](https://github.com/docsifyjs/docsify/pull/1000)) * Add a prepare script. ([#1010](https://github.com/docsifyjs/docsify/pull/1010)) -* chore(GH-action): using ubuntu 16 and removed node 8 from CI +* chore(GH-action): using ubuntu 16 and removed node 8 from CI * chore: add config ([#1014](https://github.com/docsifyjs/docsify/pull/1014)) * chore(stale): added enhancement label to exemptlabels * chore(stale): added bug label to exemptlabels -* .markdown-section max-width 800px to 80% ([#1017](https://github.com/docsifyjs/docsify/pull/1017)) -* changed the CDN from unpkg to jsDelivr #1020 ([#1022](https://github.com/docsifyjs/docsify/pull/1022)) -* migrate CI to github, refactore CI and npm scripts, linting fixes ([#1023](https://github.com/docsifyjs/docsify/pull/1023)) +* .markdown-section max-width 800px to 80% ([#1017](https://github.com/docsifyjs/docsify/pull/1017)) +* changed the CDN from unpkg to jsDelivr #1020 ([#1022](https://github.com/docsifyjs/docsify/pull/1022)) +* migrate CI to github, refactore CI and npm scripts, linting fixes ([#1023](https://github.com/docsifyjs/docsify/pull/1023)) * chore(readme): added CI badges and fixed the logo issue * added new linter config ([#1028](https://github.com/docsifyjs/docsify/pull/1028)) diff --git a/README.md b/README.md index fdef0a95d..da1f39e04 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- docsify + docsify

@@ -11,7 +11,7 @@

Backers on Open Collective - Sponsors on Open Collective + Sponsors on Open Collective Unit tests Suite Linting Checks Testing the e2e test suites @@ -41,7 +41,7 @@ ## Features - No statically built html files -- Simple and lightweight (~21kB gzipped) +- Simple and lightweight - Smart full-text search plugin - Multiple themes - Useful plugin API @@ -84,7 +84,7 @@ So that you can start straight away. - Fork it! - Create your feature branch: `git checkout -b my-new-feature` -- Commit your changes: `git commit -am 'Add some feature'` +- Commit your changes: `git add . && git commit -m 'Add some feature'` - Push to the branch: `git push origin my-new-feature` - Submit a pull request @@ -123,3 +123,9 @@ This project exists thanks to all the people who contribute. [[Contribute](CONTR ## License [MIT](LICENSE) + +## Special Thanks + +_Vercel_ has given us a Pro account. + + diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..f037a1a2a --- /dev/null +++ b/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + presets: [ + [ + '@babel/preset-env', + { + targets: { + node: 'current', + }, + }, + ], + ], +}; diff --git a/build/build.js b/build/build.js index 7dfa6b536..0de786828 100644 --- a/build/build.js +++ b/build/build.js @@ -22,14 +22,27 @@ async function build(opts) { .rollup({ input: opts.input, plugins: (opts.plugins || []).concat([ - buble(), + buble({ + transforms: { + dangerousForOf: true + }}), commonjs(), nodeResolve(), replace({ __VERSION__: version, 'process.env.SSR': false }) - ]) + ]), + onwarn: function (message) { + if (message.code === 'UNRESOLVED_IMPORT') { + throw new Error( + `Could not resolve module ` + + message.source + + `. Try running 'npm install' or using rollup's 'external' option if this is an external dependency. ` + + `Module ${message.source} is imported in ${message.importer}` + ) + } + } }) .then(function (bundle) { var dest = 'lib/' + (opts.output || opts.input) diff --git a/cypress/fixtures/tpl/docs.index.html b/cypress/fixtures/tpl/docs.index.html deleted file mode 100644 index 6a8b41a4c..000000000 --- a/cypress/fixtures/tpl/docs.index.html +++ /dev/null @@ -1,123 +0,0 @@ - - - - - docsify-e2e-tests - - - - - - - - - - - - - - - -

Loading Docsify e2e tests suite...
- - - - - - - - - - - - - diff --git a/cypress/integration/sidebar/config.spec.js b/cypress/integration/sidebar/config.spec.js deleted file mode 100644 index 4c1b511a7..000000000 --- a/cypress/integration/sidebar/config.spec.js +++ /dev/null @@ -1,344 +0,0 @@ -context('sidebar.configurations', () => { - beforeEach(() => { - cy.visit('http://localhost:3000'); - }); - - const quickStartIds = [ - 'initialize', - 'writing-content', - 'preview-your-site', - 'manual-initialization', - 'loading-dialog', - ]; - quickStartIds.forEach(id => { - it('go to #quickstart?id=' + id, () => { - cy.get( - '.sidebar-nav > :nth-child(1) > :nth-child(1) > ul > :nth-child(1) > a' - ).click(); - - cy.get(`a.section-link[href='#/quickstart?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - - const configurationIds = [ - 'el', - 'repo', - 'maxlevel', - 'loadnavbar', - 'loadsidebar', - 'hidesidebar', - 'submaxlevel', - 'auto2top', - 'homepage', - 'basepath', - 'relativepath', - 'coverpage', - 'logo', - 'name', - 'namelink', - 'markdown', - 'themecolor', - 'alias', - 'autoheader', - 'executescript', - 'noemoji', - 'mergenavbar', - 'formatupdated', - 'externallinktarget', - 'cornerexternallinktarget', - 'externallinkrel', - 'routermode', - 'nocompilelinks', - 'onlycover', - 'requestheaders', - 'ext', - 'fallbacklanguages', - 'notfoundpage', - ]; - configurationIds.forEach(id => { - it('go to #configuration?id=' + id, () => { - cy.get('[href="#/configuration"]').click(); - - cy.get(`a.section-link[href='#/configuration?id=${id}']`) - .click() - .then(() => { - cy.wait(500); // its more far from the cover - cy.matchImageSnapshot(); - }); - }); - }); - - const morePagesIds = [ - 'sidebar', - 'nested-sidebars', - 'set-page-titles-from-sidebar-selection', - 'table-of-contents', - 'ignoring-subheaders', - ]; - morePagesIds.forEach(id => { - it('go to #more-pages?id=' + id, () => { - cy.get('[href="#/more-pages"]').click(); - - cy.get(`a.section-link[href='#/more-pages?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - - const customNavbarIds = [ - 'html', - 'markdown', - 'nesting', - 'combining-custom-navbars-with-the-emoji-plugin', - ]; - customNavbarIds.forEach(id => { - it('go to #custom-navbar?id=' + id, () => { - cy.get('[href="#/custom-navbar"]').click(); - - cy.get(`a.section-link[href='#/custom-navbar?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - - const coverIds = [ - 'basic-usage', - 'custom-background', - 'coverpage-as-homepage', - 'multiple-covers', - ]; - coverIds.forEach(id => { - it('go to #cover?id=' + id, () => { - cy.get('[href="#/cover"]').click(); - - cy.get(`a.section-link[href='#/cover?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - - const themesIds = ['other-themes']; - themesIds.forEach(id => { - it('go to #themes?id=' + id, () => { - cy.get('[href="#/themes"]').click(); - - cy.get(`a.section-link[href='#/themes?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - - const pluginsIds = [ - 'full-text-search', - 'google-analytics', - 'emoji', - 'external-script', - 'zoom-image', - 'edit-on-github', - 'demo-code-with-instant-preview-and-jsfiddle-integration', - 'copy-to-clipboard', - 'disqus', - 'gitalk', - 'pagination', - 'codefund', - 'tabs', - 'more-plugins', - ]; - pluginsIds.forEach(id => { - it('go to #plugins?id=' + id, () => { - cy.get('[href="#/plugins"]').click(); - - cy.get(`a.section-link[href='#/plugins?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - - const writeAPluginIds = ['full-configuration', 'example', 'tips']; - writeAPluginIds.forEach(id => { - it('go to #write-a-plugin?id=' + id, () => { - cy.get('[href="#/write-a-plugin"]').click(); - - cy.get(`a.section-link[href='#/write-a-plugin?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - - const markdownIds = ['supports-mermaid']; - markdownIds.forEach(id => { - it('go to #markdown?id=' + id, () => { - cy.get('[href="#/markdown"]').click(); - - cy.get(`a.section-link[href='#/markdown?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - - it('go to #Language-highlight', () => { - cy.get('a[href="#/language-highlight"]') - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - - // const deployIds = [ - // 'github-pages', - // 'gitlab-pages', - // 'firebase-hosting', - // 'vps', - // 'netlify', - // 'zeit-now', - // 'aws-amplify' - // ] - // deployIds.forEach(id => { - // it('go to #deploy?id=' + id, () => { - // cy.get('[href="#/deploy"]').click() - - // cy.get(`a.section-link[href='#/deploy?id=${id}']`) - // .click() - // .then(() => { - // cy.wait(500) - // cy.matchImageSnapshot() - // }) - // }) - // }) - - const helpersIds = [ - 'important-content', - 'general-tips', - 'ignore-to-compile-link', - 'set-target-attribute-for-link', - 'disable-link', - 'github-task-lists', - 'customise-id-for-headings', - 'markdown-in-html-tag', - ]; - helpersIds.forEach(id => { - it('go to #helpers?id=' + id, () => { - cy.get('[href="#/helpers"]').click(); - - cy.get(`a.section-link[href='#/helpers?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - - const vueIds = ['basic-usage', 'combine-vuep-to-write-playground']; - vueIds.forEach(id => { - it('go to #vue?id=' + id, () => { - cy.get('[href="#/vue"]').click(); - - cy.get(`a.section-link[href='#/vue?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - - const cdnIds = [ - 'latest-version', - 'specific-version', - 'compressed-file', - 'other-cdn', - ]; - cdnIds.forEach(id => { - it('go to #cdn?id=' + id, () => { - cy.get('[href="#/cdn"]').click(); - - cy.get(`a.section-link[href='#/cdn?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - - const pwaIds = ['create-serviceworker', 'register', 'enjoy-it']; - pwaIds.forEach(id => { - it('go to #pwa?id=' + id, () => { - cy.get('[href="#/pwa"]').click(); - - cy.get(`a.section-link[href='#/pwa?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - - const ssrIds = [ - 'why-ssr', - 'quick-start', - 'custom-template', - 'configuration', - 'deploy-for-your-vps', - ]; - - ssrIds.forEach(id => { - it('go to #ssr?id=' + id, () => { - cy.get('[href="#/ssr"]').click(); - - cy.get(`a.section-link[href='#/ssr?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); - const embedFilesIds = [ - 'embedded-file-type', - 'embedded-code-fragments', - 'tag-attribute', - 'the-code-block-highlight', - ]; - embedFilesIds.forEach(id => { - it('go to #embed-files?id=' + id, () => { - cy.get('[href="#/embed-files"]').click(); - - cy.get(`a.section-link[href='#/embed-files?id=${id}']`) - .click() - .then(() => { - cy.wait(500); - cy.matchImageSnapshot(); - }); - }); - }); -}); diff --git a/cypress/live.server.js b/cypress/live.server.js deleted file mode 100644 index bb22b8f07..000000000 --- a/cypress/live.server.js +++ /dev/null @@ -1,13 +0,0 @@ -const path = require('path') -const LiveServer = require('live-server') - -const fixturePath = path.join(__dirname, './fixtures/docs') -const args = process.argv.slice(2) -console.log('[e2e tests] : args passed to live server', args) -const params = { - port: args[0] || 3000, - root: args[1] || fixturePath, - open: false - // NoBrowser: true -} -LiveServer.start(params) diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js deleted file mode 100644 index aebcffbd7..000000000 --- a/cypress/plugins/index.js +++ /dev/null @@ -1,18 +0,0 @@ -// *********************************************************** -// This example plugins/index.js can be used to load plugins -// -// You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/plugins-guide -// *********************************************************** - -// This function is called when a project is opened or re-opened (e.g. due to -// the project's config changing) -const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin') -module.exports = (on, config) => { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config - addMatchImageSnapshotPlugin(on, config) -} diff --git a/cypress/setup.js b/cypress/setup.js deleted file mode 100644 index 6372ff347..000000000 --- a/cypress/setup.js +++ /dev/null @@ -1,75 +0,0 @@ -const copyDir = require('copy-dir') -const path = require('path') -const fs = require('fs') -const { spawn } = require('child_process') - -const setup = async () => { - const PORT = process.env.PORT || 3000 - global.__LIVESERVER__ = null - global.PORT = PORT - - /** - * IN this test suite, we are going to test our docs site with all the css,js linked to our local build packages - * - * 1.1 Copy ../docs --> ./fixtures/docs - * 1.2 copy lib,themes --> ./fixtures/ - * 2. change the content of fixtures/docs/index.html to use all the links from our local build - * 3. now jest runner will run to test all the *.spec.js files - * - */ - - const shippedDirs = ['lib', 'themes'] - - // 1 - const docsPath = path.join(process.cwd(), './docs') - const fixtureDocsPath = path.join(__dirname, './fixtures/docs') - - // 1.1 - console.log('[cypress test docs] Copying the docs --> cypress/fixtures/docs') - copyDir.sync(docsPath, fixtureDocsPath) - - // 1.2 - shippedDirs.forEach(dir => { - const fromPath = path.join(process.cwd(), dir) - const toPath = path.join(__dirname, `./fixtures/docs/${dir}`) - console.log( - `[cypress test docs] Copying ${dir} --> cypress/fixtures/docs/${dir}` - ) - copyDir.sync(fromPath, toPath) - }) - - // 2 - console.log( - '[cypress test docs] Replacing content the tpl/index.html --> cypress/fixtures/docs/index.html' - ) - const indexHTMLtplPath = path.join( - __dirname, - './fixtures/tpl/docs.index.html' - ) - const fixtureIndexPath = path.join(__dirname, './fixtures/docs/index.html') - const data = fs.readFileSync(indexHTMLtplPath, 'utf8') - - // 3 - const fixturePath = path.join(__dirname, './fixtures/docs') - - fs.writeFileSync(fixtureIndexPath, data, 'utf8') - const child = spawn('node', [ - path.join(__dirname, './live.server.js'), - PORT, - fixturePath - ]) - child.on('exit', code => { - console.log(`Child process exited with code ${code}`) - }) - child.stdout.on('data', data => { - console.log(`stdout: ${data}`) - }) - child.stderr.on('data', data => { - console.log(`stderr: ${data}`) - }) - - // LiveServer.start(params) - global.__LIVESERVER__ = child -} - -setup() diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #Language-highlight.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #Language-highlight.snap.png deleted file mode 100644 index c39f80f1a..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #Language-highlight.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=compressed-file.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=compressed-file.snap.png deleted file mode 100644 index fa2acf15f..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=compressed-file.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=latest-version.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=latest-version.snap.png deleted file mode 100644 index 1ef50abe8..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=latest-version.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=other-cdn.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=other-cdn.snap.png deleted file mode 100644 index 2193959a0..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=other-cdn.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=specific-version.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=specific-version.snap.png deleted file mode 100644 index 04e364cf3..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=specific-version.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=alias.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=alias.snap.png deleted file mode 100644 index aaa0ed544..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=alias.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=auto2top.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=auto2top.snap.png deleted file mode 100644 index 2ac6312cd..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=auto2top.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=autoheader.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=autoheader.snap.png deleted file mode 100644 index 779f27af3..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=autoheader.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=basepath.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=basepath.snap.png deleted file mode 100644 index da2c844d8..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=basepath.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=cornerexternallinktarget.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=cornerexternallinktarget.snap.png deleted file mode 100644 index c41b09bbe..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=cornerexternallinktarget.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=coverpage.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=coverpage.snap.png deleted file mode 100644 index 3c05b08b0..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=coverpage.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=el.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=el.snap.png deleted file mode 100644 index d9982b684..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=el.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=executescript.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=executescript.snap.png deleted file mode 100644 index 48ca3772a..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=executescript.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=ext.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=ext.snap.png deleted file mode 100644 index 21f3e0e01..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=ext.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=externallinkrel.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=externallinkrel.snap.png deleted file mode 100644 index 52f1f0149..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=externallinkrel.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=externallinktarget.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=externallinktarget.snap.png deleted file mode 100644 index 797a914b0..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=externallinktarget.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=fallbacklanguages.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=fallbacklanguages.snap.png deleted file mode 100644 index cdb789fcc..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=fallbacklanguages.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=formatupdated.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=formatupdated.snap.png deleted file mode 100644 index b8e49a654..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=formatupdated.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=hidesidebar.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=hidesidebar.snap.png deleted file mode 100644 index cbc01ef90..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=hidesidebar.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=homepage.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=homepage.snap.png deleted file mode 100644 index b2adecfc9..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=homepage.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=loadnavbar.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=loadnavbar.snap.png deleted file mode 100644 index 71f703d11..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=loadnavbar.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=loadsidebar.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=loadsidebar.snap.png deleted file mode 100644 index 50485725b..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=loadsidebar.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=logo.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=logo.snap.png deleted file mode 100644 index bae3433a7..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=logo.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=markdown.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=markdown.snap.png deleted file mode 100644 index 4685abd7d..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=markdown.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=maxlevel.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=maxlevel.snap.png deleted file mode 100644 index 9446381a7..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=maxlevel.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=mergenavbar.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=mergenavbar.snap.png deleted file mode 100644 index a34d06cd0..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=mergenavbar.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=name.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=name.snap.png deleted file mode 100644 index 013977a49..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=name.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=namelink.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=namelink.snap.png deleted file mode 100644 index ae20a5ddb..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=namelink.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=nocompilelinks.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=nocompilelinks.snap.png deleted file mode 100644 index 619704cbe..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=nocompilelinks.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=noemoji.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=noemoji.snap.png deleted file mode 100644 index 321a77e2f..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=noemoji.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=notfoundpage.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=notfoundpage.snap.png deleted file mode 100644 index 6ccfef833..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=notfoundpage.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=onlycover.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=onlycover.snap.png deleted file mode 100644 index 3c5937436..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=onlycover.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=relativepath.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=relativepath.snap.png deleted file mode 100644 index 16c7a96ab..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=relativepath.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=repo.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=repo.snap.png deleted file mode 100644 index 8e5cd6c7d..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=repo.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=requestheaders.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=requestheaders.snap.png deleted file mode 100644 index eda49e1ec..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=requestheaders.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=routermode.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=routermode.snap.png deleted file mode 100644 index 744b49515..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=routermode.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=submaxlevel.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=submaxlevel.snap.png deleted file mode 100644 index 19bf00e35..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=submaxlevel.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=themecolor.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=themecolor.snap.png deleted file mode 100644 index 0ae49f942..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=themecolor.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=basic-usage.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=basic-usage.snap.png deleted file mode 100644 index debcf6e2c..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=basic-usage.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=coverpage-as-homepage.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=coverpage-as-homepage.snap.png deleted file mode 100644 index 51751720f..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=coverpage-as-homepage.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=custom-background.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=custom-background.snap.png deleted file mode 100644 index 17a306e13..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=custom-background.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=multiple-covers.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=multiple-covers.snap.png deleted file mode 100644 index 354dd3b69..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=multiple-covers.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=combining-custom-navbars-with-the-emoji-plugin.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=combining-custom-navbars-with-the-emoji-plugin.snap.png deleted file mode 100644 index 2fe604473..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=combining-custom-navbars-with-the-emoji-plugin.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=html.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=html.snap.png deleted file mode 100644 index 87d117c52..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=html.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=markdown.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=markdown.snap.png deleted file mode 100644 index e31a5840f..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=markdown.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=nesting.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=nesting.snap.png deleted file mode 100644 index 60effa6b9..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=nesting.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=embedded-code-fragments.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=embedded-code-fragments.snap.png deleted file mode 100644 index f8e05430c..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=embedded-code-fragments.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=embedded-file-type.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=embedded-file-type.snap.png deleted file mode 100644 index 702af8421..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=embedded-file-type.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=tag-attribute.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=tag-attribute.snap.png deleted file mode 100644 index 8b4ee81a1..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=tag-attribute.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=the-code-block-highlight.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=the-code-block-highlight.snap.png deleted file mode 100644 index 682642579..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=the-code-block-highlight.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=customise-id-for-headings.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=customise-id-for-headings.snap.png deleted file mode 100644 index 8f03a0760..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=customise-id-for-headings.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=disable-link.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=disable-link.snap.png deleted file mode 100644 index a6a717d33..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=disable-link.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=general-tips.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=general-tips.snap.png deleted file mode 100644 index 3e0e3f178..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=general-tips.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=github-task-lists.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=github-task-lists.snap.png deleted file mode 100644 index 02770c0ed..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=github-task-lists.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=ignore-to-compile-link.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=ignore-to-compile-link.snap.png deleted file mode 100644 index 8e7074c26..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=ignore-to-compile-link.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=important-content.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=important-content.snap.png deleted file mode 100644 index d8ac2fa35..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=important-content.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=markdown-in-html-tag.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=markdown-in-html-tag.snap.png deleted file mode 100644 index 842a27530..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=markdown-in-html-tag.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=set-target-attribute-for-link.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=set-target-attribute-for-link.snap.png deleted file mode 100644 index 962347631..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=set-target-attribute-for-link.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #markdownid=supports-mermaid.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #markdownid=supports-mermaid.snap.png deleted file mode 100644 index 25a0244fe..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #markdownid=supports-mermaid.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=ignoring-subheaders.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=ignoring-subheaders.snap.png deleted file mode 100644 index d94e8ff6d..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=ignoring-subheaders.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=nested-sidebars.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=nested-sidebars.snap.png deleted file mode 100644 index 726d86bf6..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=nested-sidebars.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=set-page-titles-from-sidebar-selection.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=set-page-titles-from-sidebar-selection.snap.png deleted file mode 100644 index aca69af3f..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=set-page-titles-from-sidebar-selection.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=sidebar.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=sidebar.snap.png deleted file mode 100644 index 3e3ec1552..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=sidebar.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=table-of-contents.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=table-of-contents.snap.png deleted file mode 100644 index 9d011dd48..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=table-of-contents.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=codefund.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=codefund.snap.png deleted file mode 100644 index 2e59a75b1..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=codefund.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=copy-to-clipboard.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=copy-to-clipboard.snap.png deleted file mode 100644 index 4b16c2317..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=copy-to-clipboard.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=demo-code-with-instant-preview-and-jsfiddle-integration.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=demo-code-with-instant-preview-and-jsfiddle-integration.snap.png deleted file mode 100644 index 6d38a0be9..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=demo-code-with-instant-preview-and-jsfiddle-integration.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=disqus.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=disqus.snap.png deleted file mode 100644 index a44c2de01..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=disqus.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=edit-on-github.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=edit-on-github.snap.png deleted file mode 100644 index d39fd6180..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=edit-on-github.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=emoji.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=emoji.snap.png deleted file mode 100644 index a7333e856..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=emoji.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=external-script.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=external-script.snap.png deleted file mode 100644 index c47986174..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=external-script.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=full-text-search.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=full-text-search.snap.png deleted file mode 100644 index 7205b155e..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=full-text-search.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=gitalk.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=gitalk.snap.png deleted file mode 100644 index 3b041be20..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=gitalk.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=google-analytics.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=google-analytics.snap.png deleted file mode 100644 index 411faa937..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=google-analytics.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=more-plugins.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=more-plugins.snap.png deleted file mode 100644 index 3ef52aa51..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=more-plugins.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=pagination.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=pagination.snap.png deleted file mode 100644 index 4f007a4ca..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=pagination.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=tabs.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=tabs.snap.png deleted file mode 100644 index 1bcb05baf..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=tabs.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=zoom-image.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=zoom-image.snap.png deleted file mode 100644 index e54fac3c8..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=zoom-image.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=create-serviceworker.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=create-serviceworker.snap.png deleted file mode 100644 index b90a0e883..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=create-serviceworker.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=enjoy-it.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=enjoy-it.snap.png deleted file mode 100644 index 72521e0e5..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=enjoy-it.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=register.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=register.snap.png deleted file mode 100644 index 2ddcc370f..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=register.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=initialize.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=initialize.snap.png deleted file mode 100644 index 295545618..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=initialize.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=loading-dialog.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=loading-dialog.snap.png deleted file mode 100644 index 0b770801f..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=loading-dialog.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=manual-initialization.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=manual-initialization.snap.png deleted file mode 100644 index 8fd07268f..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=manual-initialization.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=preview-your-site.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=preview-your-site.snap.png deleted file mode 100644 index f455bc5c8..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=preview-your-site.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=writing-content.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=writing-content.snap.png deleted file mode 100644 index 1c33262e1..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=writing-content.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=configuration.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=configuration.snap.png deleted file mode 100644 index 0dde65b3c..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=configuration.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=custom-template.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=custom-template.snap.png deleted file mode 100644 index e47a8c8f8..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=custom-template.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=deploy-for-your-vps.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=deploy-for-your-vps.snap.png deleted file mode 100644 index 1960a4f47..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=deploy-for-your-vps.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=quick-start.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=quick-start.snap.png deleted file mode 100644 index 1cbcfa138..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=quick-start.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=why-ssr.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=why-ssr.snap.png deleted file mode 100644 index 5a228ed17..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=why-ssr.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #themesid=other-themes.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #themesid=other-themes.snap.png deleted file mode 100644 index 2bf44b529..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #themesid=other-themes.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #vueid=basic-usage.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #vueid=basic-usage.snap.png deleted file mode 100644 index 094800a70..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #vueid=basic-usage.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #vueid=combine-vuep-to-write-playground.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #vueid=combine-vuep-to-write-playground.snap.png deleted file mode 100644 index 10bd8d6e9..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #vueid=combine-vuep-to-write-playground.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=example.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=example.snap.png deleted file mode 100644 index 7408c6a19..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=example.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=full-configuration.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=full-configuration.snap.png deleted file mode 100644 index 75bd8bb57..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=full-configuration.snap.png and /dev/null differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=tips.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=tips.snap.png deleted file mode 100644 index 889ee9d01..000000000 Binary files a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=tips.snap.png and /dev/null differ diff --git a/cypress/support/commands.js b/cypress/support/commands.js deleted file mode 100644 index 3e9454afa..000000000 --- a/cypress/support/commands.js +++ /dev/null @@ -1,41 +0,0 @@ -// *********************************************** -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add("login", (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) - -import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command' -addMatchImageSnapshotCommand({ - failureThreshold: 10.0, - failureThresholdType: 'percent', - customDiffConfig: { threshold: 10.0 }, - capture: 'viewport', - timeout: '60000' -}) -Cypress.Commands.add('setResolution', size => { - if (Cypress._.isArray(size)) { - cy.viewport(size[0], size[1]) - } else { - cy.viewport(size) - } -}) diff --git a/cypress/support/index.js b/cypress/support/index.js deleted file mode 100644 index d68db96df..000000000 --- a/cypress/support/index.js +++ /dev/null @@ -1,20 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands' - -// Alternatively you can use CommonJS syntax: -// require('./commands') diff --git a/docs/README.md b/docs/README.md index e62542032..8a7c962ca 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,7 +11,7 @@ See the [Quick start](quickstart.md) guide for more details. ## Features - No statically built html files -- Simple and lightweight (~21kB gzipped) +- Simple and lightweight - Smart full-text search plugin - Multiple themes - Useful plugin API @@ -30,3 +30,9 @@ Please consider donating if you think docsify is helpful to you or that my work ## Community Users and the development team are usually in the [Gitter chat room](https://gitter.im/docsifyjs/Lobby). + +## Special Thanks + +_Vercel_ has given us a Pro account. + + diff --git a/docs/_coverpage.md b/docs/_coverpage.md index 42652e104..557c5aa6b 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -1,10 +1,10 @@ ![logo](_media/icon.svg) -# docsify 4.11.3 +# docsify 4.11.6 > A magical documentation site generator. -- Simple and lightweight (~21kB gzipped) +- Simple and lightweight - No statically built html files - Multiple themes diff --git a/docs/_media/vercel_logo.svg b/docs/_media/vercel_logo.svg new file mode 100644 index 000000000..50a17b35e --- /dev/null +++ b/docs/_media/vercel_logo.svg @@ -0,0 +1 @@ + diff --git a/docs/_navbar.md b/docs/_navbar.md index 47a2356a9..e31e905ec 100644 --- a/docs/_navbar.md +++ b/docs/_navbar.md @@ -3,4 +3,4 @@ - [:cn: 中文](/zh-cn/) - [:de: Deutsch](/de-de/) - [:es: Spanish](/es/) - - [:ru: Russian](/ru/) + - [:ru: Russian](/ru-ru/) diff --git a/docs/cdn.md b/docs/cdn.md index 82b2d2d90..05fff3c28 100644 --- a/docs/cdn.md +++ b/docs/cdn.md @@ -44,7 +44,7 @@ Alternatively, use [compressed files](#compressed-file). ## Other CDN -- http://www.bootcdn.cn/docsify +- https://www.bootcdn.cn/docsify/ - https://cdn.jsdelivr.net/npm/docsify/ - https://cdnjs.com/libraries/docsify - +- https://unpkg.com/browse/docsify/ diff --git a/docs/configuration.md b/docs/configuration.md index 371ed35f6..7a65553a3 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -12,7 +12,7 @@ You can configure Docsify by defining `window.$docsify` as an object: ``` -The config can also be defined as a function, in which case the first arg is the Docsify `vm` instance. The function should return a config object. This can be useful for referencing `vm` in places like the markdown configuration: +The config can also be defined as a function, in which case the first argument is the Docsify `vm` instance. The function should return a config object. This can be useful for referencing `vm` in places like the markdown configuration: ```html - - - - - -
Loading ...
- + + + + + + + + - - - - - - - - - - + // Public site only + if (/docsify/.test(location.host)) { + ((window.gitter = {}).chat = {}).options = { + room: 'docsifyjs/Lobby', + }; + loadJS('//cdn.jsdelivr.net/npm/docsify@4/lib/plugins/ga.min.js'); + loadJS('//cdn.jsdelivr.net/npm/docsify@4/lib/plugins/matomo.min.js'); + loadJS('//sidecar.gitter.im/dist/sidecar.v1.js', 'async defer'); + } + })(); + + + diff --git a/docs/language-highlight.md b/docs/language-highlight.md index 0d66b55b7..1e089c10d 100644 --- a/docs/language-highlight.md +++ b/docs/language-highlight.md @@ -1,11 +1,53 @@ -# language highlight +# Language highlighting -**docsify** uses [Prism](https://github.com/PrismJS/prism) to highlight code blocks in your pages. By default it only supports CSS, JavaScript and HTML. You can make **Prism** load additional languages: +Docsify uses [Prism](https://prismjs.com) to highlight code blocks in your pages. Prism supports the following languages by default: + +* Markup - `markup`, `html`, `xml`, `svg`, `mathml`, `ssml`, `atom`, `rss` +* CSS - `css` +* C-like - `clike` +* JavaScript - `javascript`, `js` + +Support for [additional languages](https://prismjs.com/#supported-languages) is available by loading the language-specific [grammar files](https://cdn.jsdelivr.net/npm/prismjs@1/components/) via CDN: ```html - - - + + ``` -?> Check the [component files](https://github.com/PrismJS/prism/tree/gh-pages/components) list for more options. +To enable syntax highlighting, wrap each code block in triple backticks with the [language](https://prismjs.com/#supported-languages) specified on the first line: + +```` +```html +

This is a paragraph

+Docsify +``` + +```bash +echo "hello" +``` + +```php +function getAdder(int $x): int +{ + return 123; +} +``` +```` + +The above markdown will be rendered as: + +```html +

This is a paragraph

+Docsify +``` + +```bash +echo "hello" +``` + +```php +function getAdder(int $x): int +{ + return 123; +} +``` diff --git a/docs/more-pages.md b/docs/more-pages.md index d200bc7d5..0f9386848 100644 --- a/docs/more-pages.md +++ b/docs/more-pages.md @@ -51,6 +51,18 @@ Create the `_sidebar.md`: You need to create a `.nojekyll` in `./docs` to prevent GitHub Pages from ignoring files that begin with an underscore. +!> Docsify only looks for `_sidebar.md` in the current folder, and uses that, otherwise it falls back to the one configured using `window.$docsify.loadSidebar` config. + +Example file structure: + +```text +└── docs/ + ├── _sidebar.md + ├── index.md + ├── getting-started.md + └── running-services.md +``` + ## Nested Sidebars You may want the sidebar to update with only navigation to reflect the current directory. This can be done by adding a `_sidebar.md` file to each folder. @@ -102,24 +114,24 @@ A custom sidebar can also automatically generate a table of contents by setting ## Ignoring Subheaders -When `subMaxLevel` is set, each header is automatically added to the table of contents by default. If you want to ignore a specific header, add `{docsify-ignore}` to it. +When `subMaxLevel` is set, each header is automatically added to the table of contents by default. If you want to ignore a specific header, add `` to it. ```markdown # Getting Started -## Header {docsify-ignore} +## Header This header won't appear in the sidebar table of contents. ``` -To ignore all headers on a specific page, you can use `{docsify-ignore-all}` on the first header of the page. +To ignore all headers on a specific page, you can use `` on the first header of the page. ```markdown -# Getting Started {docsify-ignore-all} +# Getting Started ## Header This header won't appear in the sidebar table of contents. ``` -Both `{docsify-ignore}` and `{docsify-ignore-all}` will not be rendered on the page when used. +Both `` and `` will not be rendered on the page when used. diff --git a/docs/plugins.md b/docs/plugins.md index 2eb47ce57..c56514d1a 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -44,6 +44,17 @@ By default, the hyperlink on the current page is recognized and the content is s // To avoid search index collision // between multiple websites under the same domain namespace: 'website-1', + + // Use different indexes for path prefixes (namespaces). + // NOTE: Only works in 'auto' mode. + // + // When initialiazing an index, we look for the first path from the sidebar. + // If it matches the prefix from the list, we switch to the corresponding index. + pathNamespaces: ['/zh-cn', '/ru-ru', '/ru-ru/v1'], + + // You can provide a regexp to match prefixes. In this case, + // the matching substring will be used to identify the index + pathNamespaces: /^(\/(zh-cn|ru-ru))?(\/(v1|v2))?/ } } @@ -80,6 +91,8 @@ The default is to support parsing emoji. For example `:100:` will be parsed to : ``` +?> If you don't want to parse to emoji, you can use __colon__ or `:`. If you need to use in the title, we recommend using `:`. For example, `:100:` + ## External Script If the script on the page is an external one (imports a js file via `src` attribute), you'll need this plugin to make it work. @@ -168,22 +181,6 @@ Pagination for docsify. By [@imyelo](https://github.com/imyelo) ``` -## codefund - -a [plugin](https://github.com/njleonzhang/docsify-plugin-codefund) to make it easy to join up [codefund](https://codefund.io/) - -> codefund is formerly known as "codesponsor" - -``` - - -window.$docsify = { - plugins: [ - DocsifyCodefund.create('xxxx-xxx-xxx') // change to your codefund id - ] -} -``` - ## Tabs A docsify.js plugin for displaying tabbed content from markdown. diff --git a/docs/quickstart.md b/docs/quickstart.md index 5dc75728c..39a9328b1 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -47,7 +47,7 @@ If you don't like `npm` or have trouble installing the tool, you can manually cr - +
@@ -56,11 +56,31 @@ If you don't like `npm` or have trouble installing the tool, you can manually cr //... } - + ``` +### Specifying docsify versions + +?> Note that in both of the examples below, docsify URLs will need to be manually updated when a new major version of docsify is released (e.g. `v4.x.x` => `v5.x.x`). Check the docsify website periodically to see if a new major version has been released. + +Specifying a major version in the URL (`@4`) will allow your site will receive non-breaking enhancements (i.e. "minor" updates) and bug fixes (i.e. "patch" updates) automatically. This is the recommended way to load docsify resources. + +```html + + +``` + +If you prefer to lock docsify to a specific version, specify the full version after the `@` symbol in the URL. This is the safest way to ensure your site will look and behave the same way regardless of any changes made to future versions of docsify. + +```html + + +``` + +### Manually preview your site + If you installed python on your system, you can easily use it to run a static server to preview your site. ```bash @@ -72,17 +92,17 @@ cd docs && python -m SimpleHTTPServer 3000 If you want, you can show a loading dialog before docsify starts to render your documentation: ```html - + -
Please wait...
+
Please wait...
``` You should set the `data-app` attribute if you changed `el`: ```html - + -
Please wait...
+
Please wait...
- + + - - - + + ``` -Then you can immediately write Vue code at Markdown file. `new Vue({ el: '#main' })` script is executed by default to create instance. +#### Vue 3.x -*README.md* +```html + + + + + +``` -````markdown -# Vue guide +## Basic rendering -`v-for` usage. +Docsify will automatically render basic Vue content that does not require `data`, `methods`, or other instance features. -```html +```markdown ``` +The HTML above will render the following: + -```` -You can manually initialize a Vue instance. +## Advanced usage + +Vue components and templates that require `data`, `methods`, computed properties, lifecycle hooks, etc. require manually creating a new `Vue()` instance within a ` ``` -!> In a Markdown file, only the script within the first script tag is executed. +#### Vue 3.x -## Combine Vuep to write playground +```markdown + +``` -[Vuep](https://github.com/QingWei-Li/vuep) is a component for rendering Vue components with live editor and preview. Supports Vue component spec and JSX. +The HTML & JavaScript above will render the following: -*index.html* + -```html - - - - - - - - - - - - -``` +
+

{{ message }}

-*README.md* -```markdown -# Vuep + - + + {{ counter }} + +
- + }); -``` - -?> Example Refer to the [Vuep documentation](https://qingwei-li.github.io/vuep/). diff --git a/index.html b/index.html index 0443d1caa..bfe0778b0 100644 --- a/index.html +++ b/index.html @@ -9,10 +9,17 @@ + + @@ -26,8 +33,9 @@ '/.*/_navbar.md': '/_navbar.md', '/zh-cn/(.*)': 'https://cdn.jsdelivr.net/gh/docsifyjs/docs-zh@master/$1', '/de-de/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-de/master/$1', - '/ru/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-ru/master/$1', - '/es/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-es/master/$1' + '/ru-ru/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-ru/master/$1', + '/es/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-es/master/$1', + '/write-a-plugin': 'https://raw.githubusercontent.com/docsifyjs/docsify/master/docs/write-a-plugin.md' }, auto2top: true, basePath: '/docs/', @@ -50,10 +58,11 @@ '/de-de/': 'Suche', '/zh-cn/': '搜索', '/': 'Search' - } + }, + pathNamespaces: ['/zh-cn', '/de-de', '/ru-ru', '/es'] }, - formatUpdated: '{MM}/{DD} {HH}:{mm}', plugins: [ + DocsifyCarbon.create('CEBI6KQE', 'docsifyjsorg'), function (hook, vm) { hook.beforeEach(function (html) { if (/githubusercontent\.com/.test(vm.route.file)) { @@ -68,7 +77,6 @@ url = 'https://github.com/docsifyjs/docsify/blob/master/docs/' + vm.route.file } var editHtml = '[:memo: Edit Document](' + url + ')\n' - return editHtml + html + '\n\n----\n\n' @@ -82,9 +90,10 @@ - - - + + + + diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 000000000..8cd635e35 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,65 @@ +const path = require('path'); +const { globals: serverGlobals } = require('./test/config/server.js'); + +const sharedConfig = { + errorOnDeprecated: true, + globals: { + ...serverGlobals, // BLANK_URL, DOCS_URL, LIB_URL, NODE_MODULES_URL, TEST_HOST + DOCS_PATH: path.resolve(__dirname, 'docs'), + LIB_PATH: path.resolve(__dirname, 'lib'), + SRC_PATH: path.resolve(__dirname, 'src'), + }, + globalSetup: './test/config/jest.setup.js', + globalTeardown: './test/config/jest.teardown.js', + resetModules: true, + restoreMocks: true, +}; + +module.exports = { + // Adding globals to config root for easier importing into .eslint.js, but + // as of Jest 26.4.2 these globals need to be added to each project config + // as well. + globals: sharedConfig.globals, + projects: [ + // Unit Tests (Jest) + { + ...sharedConfig, + displayName: 'unit', + setupFilesAfterEnv: ['/test/config/jest.setup-tests.js'], + testMatch: ['/test/unit/*.test.js'], + testURL: serverGlobals.BLANK_URL, + }, + // Integration Tests (Jest) + { + ...sharedConfig, + displayName: 'integration', + setupFilesAfterEnv: ['/test/config/jest.setup-tests.js'], + testMatch: ['/test/integration/*.test.js'], + testURL: serverGlobals.BLANK_URL, + }, + // E2E Tests (Jest + Playwright) + { + ...sharedConfig, + displayName: 'e2e', + preset: 'jest-playwright-preset', + setupFilesAfterEnv: [ + '/test/config/jest-playwright.setup-tests.js', + ], + testEnvironmentOptions: { + 'jest-playwright': { + // prettier-ignore + browsers: [ + 'chromium', + 'firefox', + 'webkit', + ], + launchOptions: { + // headless: false, + // devtools: true, + }, + }, + }, + testMatch: ['/test/e2e/*.test.js'], + }, + ], +}; diff --git a/package.json b/package.json index 8fa40d055..2572f7793 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "docsify", - "version": "4.11.3", + "version": "4.11.6", "description": "A magical documentation generator.", "author": { "name": "qingwei-li", @@ -17,7 +17,6 @@ "unpkg": "lib/docsify.min.js", "files": [ "lib", - "src", "themes" ], "scripts": { @@ -28,12 +27,10 @@ "dev:ssr": "run-p serve:ssr watch:*", "lint": "eslint .", "fixlint": "eslint . --fix", - "test": "mocha ./test/**/*.test.js", - "testServer": "node cypress/setup.js", - "test:e2e": "start-server-and-test testServer http://localhost:3000 cy:run", - "posttest:e2e": "rimraf cypress/fixtures/docs", - "cy:run": "cypress run", - "cy:open": "cypress open ", + "test": "jest --runInBand", + "test:e2e": "jest --selectProjects e2e", + "test:integration": "jest --selectProjects integration", + "test:unit": "jest --selectProjects unit", "css": "node build/css", "watch:css": "npm run css -- -o themes -w", "watch:js": "node build/build.js", @@ -58,37 +55,43 @@ }, "dependencies": { "dompurify": "^2.0.8", - "marked": "^0.7.0", - "medium-zoom": "^1.0.5", + "marked": "^1.1.1", + "medium-zoom": "^1.0.6", "opencollective-postinstall": "^2.0.2", - "prismjs": "^1.19.0", + "prismjs": "^1.21.0", "strip-indent": "^3.0.0", - "tinydate": "^1.0.0", + "tinydate": "^1.3.0", "tweezer.js": "^1.4.0" }, "devDependencies": { + "@babel/core": "^7.11.6", + "@babel/preset-env": "^7.11.5", "autoprefixer-stylus": "^1.0.0", + "axios": "^0.20.0", "babel-eslint": "^10.0.3", - "chai": "^4.2.0", - "chokidar": "^3.2.1", - "conventional-changelog-cli": "^2.0.25", + "babel-jest": "^26.3.0", + "browser-sync": "^2.26.12", + "chokidar": "^3.4.2", + "common-tags": "^1.8.0", + "conventional-changelog-cli": "^2.1.0", "copy-dir": "^1.2.0", "cross-env": "^6.0.3", "cssnano": "^4.1.10", - "cypress": "^3.8.1", - "cypress-image-snapshot": "^3.1.1", "eslint": "^5.16.0", "eslint-plugin-import": "^2.20.1", + "eslint-plugin-jest": "^24.0.2", + "eslint-plugin-jest-playwright": "^0.2.1", "eslint-plugin-prettier": "^3.1.2", - "esm": "^3.1.4", "husky": "^3.1.0", - "jsdom": "^16.2.2", + "jest": "^26.4.2", + "jest-image-snapshot": "^4.2.0", + "jest-playwright-preset": "^1.3.1", "lerna": "^3.22.1", - "lint-staged": "^10.1.2", + "lint-staged": "^10.4.0", "live-server": "^1.2.1", "mkdirp": "^0.5.1", - "mocha": "^5.2.0", "npm-run-all": "^4.1.5", + "playwright": "^1.4.1", "prettier": "^1.19.1", "rimraf": "^3.0.0", "rollup": "^1.23.1", @@ -99,8 +102,10 @@ "rollup-plugin-replace": "^2.2.0", "rollup-plugin-uglify": "^6.0.4", "serve-handler": "^6.1.2", - "start-server-and-test": "^1.10.6", - "stylus": "^0.54.5" + "stylus": "^0.54.5", + "vue2": "npm:vue@^2.6.12", + "vue3": "npm:vue@^3.0.0", + "xhr-mock": "^2.5.1" }, "keywords": [ "doc", diff --git a/packages/docsify-server-renderer/README.md b/packages/docsify-server-renderer/README.md index 76c5f80dc..9968b1e0b 100644 --- a/packages/docsify-server-renderer/README.md +++ b/packages/docsify-server-renderer/README.md @@ -14,7 +14,7 @@ var readFileSync = require('fs').readFileSync // init var renderer = new Renderer({ - template: readFileSync('./docs/index.template.html', 'utf-8')., + template: readFileSync('./docs/index.template.html', 'utf-8'), config: { name: 'docsify', repo: 'docsifyjs/docsify' @@ -35,12 +35,12 @@ renderer.renderToString(url) docsify - + - + ``` diff --git a/packages/docsify-server-renderer/package.json b/packages/docsify-server-renderer/package.json index 0f226841a..fecc1ac23 100644 --- a/packages/docsify-server-renderer/package.json +++ b/packages/docsify-server-renderer/package.json @@ -1,6 +1,6 @@ { "name": "docsify-server-renderer", - "version": "4.11.2", + "version": "4.11.6", "description": "docsify server renderer", "author": { "name": "qingwei-li", @@ -15,9 +15,9 @@ "test": "echo 'hello'" }, "dependencies": { - "debug": "^4.1.1", - "docsify": "^4.11.2", - "dompurify": "^2.0.8", + "debug": "^4.3.0", + "docsify": "^4.11.6", + "dompurify": "^2.1.1", "node-fetch": "^2.6.0", "resolve-pathname": "^3.0.0" } diff --git a/src/core/event/scroll.js b/src/core/event/scroll.js index 946589996..bd6661918 100644 --- a/src/core/event/scroll.js +++ b/src/core/event/scroll.js @@ -18,7 +18,8 @@ function scrollTo(el, offset = 0) { enableScrollEvent = false; scroller = new Tweezer({ start: window.pageYOffset, - end: el.getBoundingClientRect().top + window.pageYOffset - offset, + end: + Math.round(el.getBoundingClientRect().top) + window.pageYOffset - offset, duration: 500, }) .on('tick', v => window.scrollTo(0, v)) @@ -79,9 +80,12 @@ function highlight(path) { const isInView = active.offsetTop >= wrap.scrollTop && cur <= wrap.scrollTop + height; const notThan = cur - curOffset < height; - const top = isInView ? wrap.scrollTop : notThan ? curOffset : cur - height; - sidebar.scrollTop = top; + sidebar.scrollTop = isInView + ? wrap.scrollTop + : notThan + ? curOffset + : cur - height; } } diff --git a/src/core/event/sidebar.js b/src/core/event/sidebar.js index b15cb2afe..0e1f028c1 100644 --- a/src/core/event/sidebar.js +++ b/src/core/event/sidebar.js @@ -86,6 +86,8 @@ export function getAndActive(router, el, isParent, autoTitle) { const href = a.getAttribute('href'); const node = isParent ? a.parentNode : a; + a.title = a.title || a.innerText; + if (hash.indexOf(href) === 0 && !target) { target = a; dom.toggleClass(node, 'add', 'active'); diff --git a/src/core/fetch/index.js b/src/core/fetch/index.js index 0afef2a22..654c8929d 100644 --- a/src/core/fetch/index.js +++ b/src/core/fetch/index.js @@ -62,7 +62,7 @@ export function fetchMixin(proto) { case 'object': key = Object.keys(notFoundPage) .sort((a, b) => b.length - a.length) - .find(key => path.match(new RegExp('^' + key))); + .find(k => path.match(new RegExp('^' + k))); path404 = (key && notFoundPage[key]) || defaultPath; break; @@ -112,7 +112,7 @@ export function fetchMixin(proto) { this._loadSideAndNav(path, qs, loadSidebar, cb) ), _ => { - this._fetchFallbackPage(file, qs, cb) || this._fetch404(file, qs, cb); + this._fetchFallbackPage(path, qs, cb) || this._fetch404(file, qs, cb); } ); @@ -198,7 +198,9 @@ export function fetchMixin(proto) { return false; } - const newPath = path.replace(new RegExp(`^/${local}`), ''); + const newPath = this.router.getFile( + path.replace(new RegExp(`^/${local}`), '') + ); const req = request(newPath + qs, true, requestHeaders); req.then( diff --git a/src/core/init/lifecycle.js b/src/core/init/lifecycle.js index d8106adc9..d695ed6e6 100644 --- a/src/core/init/lifecycle.js +++ b/src/core/init/lifecycle.js @@ -18,21 +18,22 @@ export function initLifecycle(vm) { }); } -export function callHook(vm, hook, data, next = noop) { - const queue = vm._hooks[hook]; +export function callHook(vm, hookName, data, next = noop) { + const queue = vm._hooks[hookName]; const step = function(index) { - const hook = queue[index]; + const hookFn = queue[index]; + if (index >= queue.length) { next(data); - } else if (typeof hook === 'function') { - if (hook.length === 2) { - hook(data, result => { + } else if (typeof hookFn === 'function') { + if (hookFn.length === 2) { + hookFn(data, result => { data = result; step(index + 1); }); } else { - const result = hook(data); + const result = hookFn(data); data = result === undefined ? data : result; step(index + 1); } diff --git a/src/core/render/compiler.js b/src/core/render/compiler.js index 4eaf51215..557507721 100644 --- a/src/core/render/compiler.js +++ b/src/core/render/compiler.js @@ -5,7 +5,7 @@ import { tree as treeTpl } from './tpl'; import { genTree } from './gen-tree'; import { slugify } from './slugify'; import { emojify } from './emojify'; -import { getAndRemoveConfig } from './utils'; +import { getAndRemoveConfig, removeAtag } from './utils'; import { imageCompiler } from './compiler/image'; import { highlightCodeCompiler } from './compiler/code'; import { paragraphCompiler } from './compiler/paragraph'; @@ -206,17 +206,29 @@ export class Compiler { */ origin.heading = renderer.heading = function(text, level) { let { str, config } = getAndRemoveConfig(text); - const nextToc = { level, title: str }; + const nextToc = { level, title: removeAtag(str) }; + + if (//g.test(str)) { + str = str.replace('', ''); + nextToc.title = removeAtag(str); + nextToc.ignoreSubHeading = true; + } if (/{docsify-ignore}/g.test(str)) { str = str.replace('{docsify-ignore}', ''); - nextToc.title = str; + nextToc.title = removeAtag(str); nextToc.ignoreSubHeading = true; } + if (//g.test(str)) { + str = str.replace('', ''); + nextToc.title = removeAtag(str); + nextToc.ignoreAllSubs = true; + } + if (/{docsify-ignore-all}/g.test(str)) { str = str.replace('{docsify-ignore-all}', ''); - nextToc.title = str; + nextToc.title = removeAtag(str); nextToc.ignoreAllSubs = true; } @@ -267,7 +279,7 @@ export class Compiler { // Remove headers who are under current header for ( let j = i; - deletedHeaderLevel < toc[j].level && j < toc.length; + j < toc.length && deletedHeaderLevel < toc[j].level; j++ ) { toc.splice(j, 1) && j-- && i++; diff --git a/src/core/render/compiler/code.js b/src/core/render/compiler/code.js index da470d78f..2aa14debb 100644 --- a/src/core/render/compiler/code.js +++ b/src/core/render/compiler/code.js @@ -3,11 +3,12 @@ import Prism from 'prismjs'; import 'prismjs/components/prism-markup-templating'; export const highlightCodeCompiler = ({ renderer }) => - (renderer.code = function(code, lang = '') { + (renderer.code = function(code, lang = 'markup') { const langOrMarkup = Prism.languages[lang] || Prism.languages.markup; const text = Prism.highlight( code.replace(/@DOCSIFY_QM@/g, '`'), - langOrMarkup + langOrMarkup, + lang ); return `
${text}
`; diff --git a/src/core/render/compiler/headline.js b/src/core/render/compiler/headline.js index 3f5c22039..61e4b3fb9 100644 --- a/src/core/render/compiler/headline.js +++ b/src/core/render/compiler/headline.js @@ -1,20 +1,32 @@ -import { getAndRemoveConfig } from '../utils'; +import { getAndRemoveConfig, removeAtag } from '../utils'; import { slugify } from './slugify'; export const headingCompiler = ({ renderer, router, _self }) => (renderer.code = (text, level) => { let { str, config } = getAndRemoveConfig(text); - const nextToc = { level, title: str }; + const nextToc = { level, title: removeAtag(str) }; + + if (//g.test(str)) { + str = str.replace('', ''); + nextToc.title = removeAtag(str); + nextToc.ignoreSubHeading = true; + } if (/{docsify-ignore}/g.test(str)) { str = str.replace('{docsify-ignore}', ''); - nextToc.title = str; + nextToc.title = removeAtag(str); nextToc.ignoreSubHeading = true; } + if (//g.test(str)) { + str = str.replace('', ''); + nextToc.title = removeAtag(str); + nextToc.ignoreAllSubs = true; + } + if (/{docsify-ignore-all}/g.test(str)) { str = str.replace('{docsify-ignore-all}', ''); - nextToc.title = str; + nextToc.title = removeAtag(str); nextToc.ignoreAllSubs = true; } diff --git a/src/core/render/embed.js b/src/core/render/embed.js index d31cd2b02..5159754ab 100644 --- a/src/core/render/embed.js +++ b/src/core/render/embed.js @@ -14,6 +14,7 @@ function walkFetchEmbed({ embedTokens, compile, fetch }, cb) { } while ((token = embedTokens[step++])) { + // eslint-disable-next-line no-shadow const next = (function(token) { return text => { let embedToken; @@ -101,7 +102,7 @@ export function prerenderEmbed({ compiler, raw = '', fetch }, done) { const compile = compiler._marked; let tokens = compile.lexer(raw); const embedTokens = []; - const linkRE = compile.InlineLexer.rules.link; + const linkRE = compile.Lexer.rules.inline.link; const links = tokens.links; tokens.forEach((token, index) => { diff --git a/src/core/render/index.js b/src/core/render/index.js index 3d65a5335..750f1d4dd 100644 --- a/src/core/render/index.js +++ b/src/core/render/index.js @@ -27,9 +27,7 @@ function executeScript() { return false; } - setTimeout(_ => { - window.__EXECUTE_RESULT__ = new Function(code)(); - }, 0); + new Function(code)(); } function formatUpdated(html, updated, fn) { @@ -49,22 +47,56 @@ function renderMain(html) { } this._renderTo('.markdown-section', html); + // Render sidebar with the TOC !this.config.loadSidebar && this._renderSidebar(); - // Execute script + // Execute markdown - - `; - } - - const rootPath = path.join(__dirname, 'fixtures', fixture); - - const dom = initJSDOM(markup); - dom.reconfigure({ url: 'file:///' + rootPath }); - - // Mimic src/core/index.js but for Node.js - function Docsify() { - this._init(); - } - - const proto = Docsify.prototype; - - const { initMixin } = require('../src/core/init'); - const { routerMixin } = require('../src/core//router'); - const { renderMixin } = require('../src/core//render'); - const { fetchMixin } = require('../src/core/fetch'); - const { eventMixin } = require('../src/core//event'); - - initMixin(proto); - routerMixin(proto); - renderMixin(proto); - fetchMixin(proto); - eventMixin(proto); - - const NOT_INIT_PATTERN = ''; - - return new Promise(resolve => { - ready(() => { - const docsify = new Docsify(); - // NOTE: I was not able to get it working with a callback, but polling works usually at the first time - const id = setInterval(() => { - if ( - dom.window.document.body.innerHTML.indexOf(NOT_INIT_PATTERN) === -1 - ) { - clearInterval(id); - return resolve({ - docsify: docsify, - dom: dom, - }); - } - }, 10); - }); - }); -}; - -module.exports.expectSameDom = function(actual, expected) { - const WHITESPACES_BETWEEN_TAGS = />(\s\s+) { + // Storing separate image comparison configurations for easy switching while + // evaluating results. Once more e2e tests are in place, we'll settle on a + // configuration, allowing us to safely remove the multi-config object below. + const config = { + // Pixel-based image comparisons + // https://github.com/mapbox/pixelmatch#pixelmatchimg1-img2-output-width-height-options + pixelCompare: { + customDiffConfig: { + threshold: 0.3, + }, + failureThreshold: 0.04, + }, + // Structural Similarity Index Measure (SSIM) comparisons + // https://github.com/obartra/ssim + ssimCompare: { + comparisonMethod: 'ssim', + failureThreshold: 0.15, + }, + }; + + const toMatchImageSnapshot = configureToMatchImageSnapshot({ + allowSizeMismatch: true, // Windows CI fix + customSnapshotIdentifier(data) { + return `${data.defaultIdentifier}-${browserName}`; + }, + diffDirection: 'vertical', + failureThresholdType: 'percent', + noColors: true, + runInProcess: true, // macOS CI fix + // pixel- or ssim-based configuration + ...config.pixelCompare, + }); + + expect.extend({ toMatchImageSnapshot }); +}); + +beforeEach(async () => { + await global.jestPlaywright.resetPage(); + + // Goto URL () + // https://playwright.dev/#path=docs%2Fapi.md&q=pagegotourl-options + // NOTE: Tests typically begin by navigating to a page for testing. When + // this doesn't happen, Playwright operates on the "about:blank" page which + // will cause operations that require the window location to be a valid URL + // to fail (e.g. AJAX requests). To avoid these issues, this hook ensures + // that each tests begins by a blank HTML page. + await page.goto(BLANK_URL); +}); diff --git a/test/config/jest.setup-tests.js b/test/config/jest.setup-tests.js new file mode 100644 index 000000000..2d29eb858 --- /dev/null +++ b/test/config/jest.setup-tests.js @@ -0,0 +1,42 @@ +// Lifecycle Hooks +// ----------------------------------------------------------------------------- +// Soft-reset jsdom. This clears the DOM and removes all attribute from the +// root element, however it does not undo changes made to jsdom globals like +// the window or document object. Tests requiring a full jsdom reset should be +// stored in separate files, as this is the only way (?) to do a complete +// reset of JSDOM with Jest. +beforeEach(async () => { + const rootElm = document.documentElement; + + // Remove elements (faster the setting innerHTML) + while (rootElm.firstChild) { + rootElm.removeChild(rootElm.firstChild); + } + + // Remove docsify side-effects + [ + '__current_docsify_compiler__', + '_paq', + '$docsify', + 'Docsify', + 'DocsifyCompiler', + 'ga', + 'gaData', + 'gaGlobal', + 'gaplugins', + 'gitter', + 'google_tag_data', + 'marked', + 'Prism', + ].forEach(prop => { + if (global[prop]) { + delete global[prop]; + } + }); + + // Remove attributes + [...rootElm.attributes].forEach(attr => rootElm.removeAttribute(attr.name)); + + // Restore base elements + rootElm.innerHTML = ''; +}); diff --git a/test/config/jest.setup.js b/test/config/jest.setup.js new file mode 100644 index 000000000..42f922180 --- /dev/null +++ b/test/config/jest.setup.js @@ -0,0 +1,5 @@ +const server = require('./server.js'); + +module.exports = async () => { + await server.startAsync(); +}; diff --git a/test/config/jest.teardown.js b/test/config/jest.teardown.js new file mode 100644 index 000000000..647b2cea9 --- /dev/null +++ b/test/config/jest.teardown.js @@ -0,0 +1,5 @@ +const server = require('./server.js'); + +module.exports = async () => { + server.stop(); +}; diff --git a/test/config/server.js b/test/config/server.js new file mode 100644 index 000000000..d027cdb0e --- /dev/null +++ b/test/config/server.js @@ -0,0 +1,125 @@ +const browserSync = require('browser-sync').create(); +const path = require('path'); + +const hasStartArg = process.argv.includes('--start'); + +const serverConfig = { + host: '127.0.0.1', + port: 3001, +}; + +function startServer(options = {}, cb = Function.prototype) { + const defaults = { + ...serverConfig, + middleware: [ + { + route: '/_blank.html', + handle: function(req, res, next) { + res.setHeader('Content-Type', 'text/html'); + res.end(''); + next(); + }, + }, + ], + notify: false, + open: false, + rewriteRules: [ + // Replace docsify-related CDN URLs with local paths + { + match: /(https?:)?\/\/cdn\.jsdelivr\.net\/npm\/docsify(@\d?\.?\d?\.?\d)?\/lib\//g, + replace: '/lib/', + }, + ], + server: { + baseDir: path.resolve(__dirname, '../'), + routes: { + '/docs': path.resolve(__dirname, '../../docs'), + '/docs/changelog.md': './CHANGELOG.md', + '/lib': path.resolve(__dirname, '../../lib'), + '/node_modules': path.resolve(__dirname, '../../node_modules'), + }, + }, + snippetOptions: { + rule: { + match: /<\/body>/i, + fn: function(snippet, match) { + // Override changelog alias to load local changelog (see routes) + const injectJS = ` + + `; + + return injectJS + snippet + match; + }, + }, + }, + startPath: '/docs', + ui: false, + }; + + console.log('\n'); + + browserSync.init( + // Config + { + ...defaults, + ...options, + }, + // Callback + cb + ); +} + +async function startServerAsync() { + await new Promise((resolve, reject) => { + startServer({}, () => { + console.log('\n'); + resolve(); + }); + }); +} + +function stopServer() { + browserSync.exit(); +} + +// Allow starting the test server from the CLI. Useful for viewing test content +// like fixtures (/index.html)) and local docs site (/docs) used for testing. +if (hasStartArg) { + startServer({ + open: true, + port: serverConfig.port + 1, + directory: true, + }); +} +// Display friendly message about manually starting a server instance +else if (require.main === module) { + console.info('Use --start argument to manually start server instance'); +} + +module.exports = { + globals: { + get BLANK_URL() { + return `${this.TEST_HOST}/_blank.html`; + }, + get DOCS_URL() { + return `${this.TEST_HOST}/docs`; + }, + get LIB_URL() { + return `${this.TEST_HOST}/lib`; + }, + get NODE_MODULES_URL() { + return `${this.TEST_HOST}/node_modules`; + }, + TEST_HOST: `http://${serverConfig.host}:${serverConfig.port}`, + }, + start: startServer, + startAsync: startServerAsync, + stop: stopServer, +}; diff --git a/test/e2e/.eslintrc.js b/test/e2e/.eslintrc.js new file mode 100644 index 000000000..5f3fcf676 --- /dev/null +++ b/test/e2e/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ['plugin:jest-playwright/recommended'], +}; diff --git a/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-1-chromium-snap.png b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-1-chromium-snap.png new file mode 100644 index 000000000..55dba7563 Binary files /dev/null and b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-1-chromium-snap.png differ diff --git a/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-1-firefox-snap.png b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-1-firefox-snap.png new file mode 100644 index 000000000..140788ec0 Binary files /dev/null and b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-1-firefox-snap.png differ diff --git a/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-1-webkit-snap.png b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-1-webkit-snap.png new file mode 100644 index 000000000..75bbc8e4d Binary files /dev/null and b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-1-webkit-snap.png differ diff --git a/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-2-chromium-snap.png b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-2-chromium-snap.png new file mode 100644 index 000000000..3201212e1 Binary files /dev/null and b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-2-chromium-snap.png differ diff --git a/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-2-firefox-snap.png b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-2-firefox-snap.png new file mode 100644 index 000000000..53fe158fe Binary files /dev/null and b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-2-firefox-snap.png differ diff --git a/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-2-webkit-snap.png b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-2-webkit-snap.png new file mode 100644 index 000000000..ea197cee5 Binary files /dev/null and b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-2-webkit-snap.png differ diff --git a/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-3-chromium-snap.png b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-3-chromium-snap.png new file mode 100644 index 000000000..8a2cb7bed Binary files /dev/null and b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-3-chromium-snap.png differ diff --git a/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-3-firefox-snap.png b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-3-firefox-snap.png new file mode 100644 index 000000000..c1987807e Binary files /dev/null and b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-3-firefox-snap.png differ diff --git a/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-3-webkit-snap.png b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-3-webkit-snap.png new file mode 100644 index 000000000..3e0a1710c Binary files /dev/null and b/test/e2e/__image_snapshots__/example-test-js-example-tests-image-snapshots-3-webkit-snap.png differ diff --git a/test/e2e/example.test.js b/test/e2e/example.test.js new file mode 100644 index 000000000..34aa84aa1 --- /dev/null +++ b/test/e2e/example.test.js @@ -0,0 +1,344 @@ +// Modules, constants, and variables +// ----------------------------------------------------------------------------- +const docsifyInit = require('../helpers/docsify-init'); + +// Suite +// ----------------------------------------------------------------------------- +describe(`Example Tests`, function() { + // Tests + // --------------------------------------------------------------------------- + test('dom manipulation', async () => { + const testText = 'This is a test'; + const testHTML = `

Test

${testText}

`; + + // Inject HTML + // https://playwright.dev/#path=docs%2Fapi.md&q=pagesetcontenthtml-options + await page.setContent(testHTML); + + // Add class to element and test + // https://playwright.dev/#path=docs%2Fapi.md&q=pageevalselector-pagefunction-arg + await page.$eval('body', elm => elm.classList.add('foo')); + expect(await page.getAttribute('body', 'class')).toEqual('foo'); + + // Test using helper methods from expect-playright (via jest-playwright) + // https://github.com/playwright-community/expect-playwright + // https://playwright.tech/blog/using-jest-with-playwright + await expect(page).toHaveText('body', 'Test'); + await expect(page).toHaveSelector('p'); + await expect(page).toEqualText('p', testText); + await expect(page).not.toHaveSelector('table', { timeout: 1 }); + + // Test using standard jest + playwrite methods + // https://playwright.dev/#path=docs%2Fapi.md&q=pagetextcontentselector-options + expect(await page.textContent('body')).toMatch(/Test/); + await page.waitForSelector('p'); + expect(await page.textContent('p')).toEqual(testText); + await page.waitForSelector('table', { state: 'detached' }); + + // Debug mode + // https://github.com/playwright-community/jest-playwright#put-in-debug-mode + // await jestPlaywright.debug(); + }); + + test('javascript in browser context', async () => { + // Get native DOM values + // https://playwright.dev/#path=docs%2Fapi.md&q=pageevaluatepagefunction-arg + const clientDimensions = await page.evaluate(() => { + return { + width: document.documentElement.clientWidth, + height: document.documentElement.clientHeight, + }; + }); + + expect(clientDimensions).toHaveProperty('width'); + expect(typeof clientDimensions.width).toBe('number'); + expect(clientDimensions).toHaveProperty('height'); + expect(typeof clientDimensions.height).toBe('number'); + + // Get result of script executed in browser context + // https://playwright.dev/#path=docs%2Fapi.md&q=pageevaluatepagefunction-arg + const scriptResult = await page.evaluate( + numbers => { + const result = numbers.reduce( + (accumulator, currentValue) => accumulator + currentValue + ); + + return Promise.resolve(result); + }, + [1, 2, 3] + ); + + expect(scriptResult).toBe(6); + + // Get result of local function executed in browser context + // https://playwright.dev/#path=docs%2Fapi.md&q=pageevaluatepagefunction-arg + function add(...addends) { + return addends.reduce( + (accumulator, currentValue) => accumulator + currentValue + ); + } + + const functionResult = await page.evaluate(` + ${add.toString()} + + const result = add(1, 2, 3); + + Promise.resolve(result); + `); + + expect(functionResult).toBe(6); + }); + + test('manual docsify site using playwright methods', async () => { + // Goto URL + // https://playwright.dev/#path=docs%2Fapi.md&q=pagegotourl-options + await page.goto(BLANK_URL); + + // Set docsify configuration + // https://playwright.dev/#path=docs%2Fapi.md&q=pageevaluatepagefunction-arg + await page.evaluate(() => { + window.$docsify = { + el: '#app', + basePath: '/docs', + themeColor: 'red', + }; + }); + + // Add docsify target element + // https://playwright.dev/#path=docs%2Fapi.md&q=pageevalselector-pagefunction-arg + await page.$eval('body', elm => { + elm.innerHTML = '
'; + }); + + // Inject docsify theme (vue.css) + // https://playwright.dev/#path=docs%2Fapi.md&q=pageaddstyletagoptions + await page.addStyleTag({ url: `${LIB_URL}/themes/vue.css` }); + + // Inject docsify.js + // https://playwright.dev/#path=docs%2Fapi.md&q=pageaddscripttagoptions + await page.addScriptTag({ url: `${LIB_URL}/docsify.js` }); + + // Wait for docsify to initialize + // https://playwright.dev/#path=docs%2Fapi.md&q=pagewaitforselectorselector-options + await page.waitForSelector('#main'); + + // Create handle for JavaScript object in browser + // https://playwright.dev/#path=docs%2Fapi.md&q=pageevaluatepagefunction-arg + const $docsify = await page.evaluate(() => window.$docsify); + + // Test object property and value + expect($docsify).toHaveProperty('themeColor', 'red'); + }); + + test('Docsify /docs/ site using docsifyInit()', async () => { + // Load custom docsify + // (See ./helpers/docsifyInit.js for details) + await docsifyInit({ + config: { + basePath: '/docs/', + }, + // _debug: true, + // _logHTML: true, + }); + + // Create handle for JavaScript object in browser + // https://playwright.dev/#path=docs%2Fapi.md&q=pageevaluatepagefunction-arg + const $docsify = await page.evaluate(() => window.$docsify); + + // Verify config options + expect(typeof $docsify).toEqual('object'); + + // Verify docsifyInitConfig.markdown content was rendered + await expect(page).toHaveText( + '#main', + 'A magical documentation site generator' + ); + }); + + test('custom docsify site using docsifyInit()', async () => { + const docsifyInitConfig = { + config: { + name: 'Docsify Name', + themeColor: 'red', + }, + markdown: { + coverpage: ` + # Docsify Test + + > Testing a magical documentation site generator + + [GitHub](https://github.com/docsifyjs/docsify/) + `, + homepage: ` + # Hello World + + This is the homepage. + `, + navbar: ` + - [docsify.js.org](https://docsify.js.org/#/) + `, + sidebar: ` + - [Test Page](test) + `, + }, + routes: { + '/test.md': ` + # Test Page + + This is a custom route. + `, + '/data-test-scripturls.js': ` + document.body.setAttribute('data-test-scripturls', 'pass'); + `, + }, + script: ` + document.body.setAttribute('data-test-script', 'pass'); + `, + scriptURLs: [ + // docsifyInit() route + '/data-test-scripturls.js', + // Server route + '/lib/plugins/search.min.js', + ], + style: ` + body { + background: red !important; + } + `, + styleURLs: ['/lib/themes/vue.css'], + }; + + await docsifyInit({ + ...docsifyInitConfig, + // _debug: true, + // _logHTML: true, + }); + + const $docsify = await page.evaluate(() => window.$docsify); + + // Verify config options + expect(typeof $docsify).toEqual('object'); + expect($docsify).toHaveProperty('themeColor', 'red'); + await expect(page).toHaveText('.app-name', 'Docsify Name'); + + // Verify docsifyInitConfig.markdown content was rendered + await expect(page).toHaveText('section.cover', 'Docsify Test'); // Coverpage + await expect(page).toHaveText('nav.app-nav', 'docsify.js.org'); // Navbar + await expect(page).toHaveText('aside.sidebar', 'Test Page'); // Sidebar + await expect(page).toHaveText('#main', 'This is the homepage'); // Homepage + + // Verify docsifyInitConfig.scriptURLs were added to the DOM + for (const scriptURL of docsifyInitConfig.scriptURLs) { + await expect(page).toHaveSelector(`script[src$="${scriptURL}"]`, { + state: 'attached', + }); + } + + // Verify docsifyInitConfig.scriptURLs were executed + await expect(page).toHaveSelector('body[data-test-scripturls]'); + await expect(page).toHaveSelector('.search input[type="search"]'); + + // Verify docsifyInitConfig.script was added to the DOM + expect( + await page.evaluate(scriptText => { + return [...document.querySelectorAll('script')].some( + elm => elm.textContent.replace(/\s+/g, '') === scriptText + ); + }, docsifyInitConfig.script.replace(/\s+/g, '')) + ).toBe(true); + + // Verify docsifyInitConfig.script was executed + await expect(page).toHaveSelector('body[data-test-script]'); + + // Verify docsifyInitConfig.styleURLs were added to the DOM + for (const styleURL of docsifyInitConfig.styleURLs) { + await expect(page).toHaveSelector( + `link[rel*="stylesheet"][href$="${styleURL}"]`, + { + state: 'attached', + } + ); + } + + // Verify docsifyInitConfig.style was added to the DOM + expect( + await page.evaluate(styleText => { + return [...document.querySelectorAll('style')].some( + elm => elm.textContent.replace(/\s+/g, '') === styleText + ); + }, docsifyInitConfig.style.replace(/\s+/g, '')) + ).toBe(true); + + // Verify docsify navigation and docsifyInitConfig.routes + await page.click('a[href="#/test"]'); + expect(page.url()).toMatch(/\/test$/); + await expect(page).toHaveText('#main', 'This is a custom route'); + }); + + test('image snapshots', async () => { + await docsifyInit({ + config: { + name: 'Docsify Test', + }, + markdown: { + homepage: ` + # The Cosmos Awaits + + [Carl Sagan](https://en.wikipedia.org/wiki/Carl_Sagan) + + Cosmic ocean take root and flourish decipherment hundreds of thousands + dream of the mind's eye courage of our questions. At the edge of forever + network of wormholes ship of the imagination two ghostly white figures + in coveralls and helmets are softly dancing are creatures of the cosmos + the only home we've ever known? How far away emerged into consciousness + bits of moving fluff gathered by gravity with pretty stories for which + there's little good evidence vanquish the impossible. + + The ash of stellar alchemy permanence of the stars shores of the cosmic + ocean billions upon billions Drake Equation finite but unbounded. + Hundreds of thousands cosmic ocean hearts of the stars Hypatia invent + the universe hearts of the stars? Realm of the galaxies muse about dream + of the mind's eye hundreds of thousands the only home we've ever known + how far away. Extraordinary claims require extraordinary evidence + citizens of distant epochs invent the universe as a patch of light the + carbon in our apple pies gathered by gravity. + + Billions upon billions gathered by gravity white dwarf intelligent + beings vanquish the impossible descended from astronomers. A still more + glorious dawn awaits cosmic ocean star stuff harvesting star light the + sky calls to us kindling the energy hidden in matter rich in heavy + atoms. A mote of dust suspended in a sunbeam across the centuries the + only home we've ever known bits of moving fluff a very small stage in a + vast cosmic arena courage of our questions. + + Euclid the only home we've ever known realm of the galaxies trillion + radio telescope Apollonius of Perga. The carbon in our apple pies invent + the universe muse about stirred by starlight great turbulent clouds + emerged into consciousness? Invent the universe vastness is bearable + only through love a still more glorious dawn awaits descended from + astronomers as a patch of light the sky calls to us. Great turbulent + clouds citizens of distant epochs invent the universe two ghostly white + figures in coveralls and helmets are softly dancing courage of our + questions rich in heavy atoms and billions upon billions upon billions + upon billions upon billions upon billions upon billions. + `, + }, + styleURLs: [`/lib/themes/vue.css`], + // _debug: true, + // _logHTML: true, + }); + + // Viewport screenshot + const screenshot1 = await page.screenshot(); + expect(screenshot1).toMatchImageSnapshot(); + + // Full page screenshot + const screenshot2 = await page.screenshot({ fullPage: true }); + expect(screenshot2).toMatchImageSnapshot(); + + // Element screenshot + const elmHandle = await page.$('h1'); + const screenshot3 = await elmHandle.screenshot(); + expect(screenshot3).toMatchImageSnapshot(); + }); +}); diff --git a/test/e2e/search.test.js b/test/e2e/search.test.js new file mode 100644 index 000000000..3866b4250 --- /dev/null +++ b/test/e2e/search.test.js @@ -0,0 +1,38 @@ +const docsifyInit = require('../helpers/docsify-init'); + +// Suite +// ----------------------------------------------------------------------------- +describe('Search Plugin Tests', function() { + // Tests + // --------------------------------------------------------------------------- + test('search readme', async () => { + const docsifyInitConfig = { + markdown: { + homepage: ` + # Hello World + + This is the homepage. + `, + sidebar: ` + - [Home page](/) + - [Test Page](test) + `, + }, + routes: { + '/test.md': ` + # Test Page + + This is a custom route. + `, + }, + scriptURLs: ['/lib/plugins/search.min.js'], + }; + + await docsifyInit(docsifyInitConfig); + await page.fill('input[type=search]', 'hello'); + await expect(page).toEqualText('.results-panel h2', 'Hello World'); + await page.click('.clear-button'); + await page.fill('input[type=search]', 'test'); + await expect(page).toEqualText('.results-panel h2', 'Test Page'); + }); +}); diff --git a/test/e2e/vue.test.js b/test/e2e/vue.test.js new file mode 100644 index 000000000..395eac573 --- /dev/null +++ b/test/e2e/vue.test.js @@ -0,0 +1,141 @@ +const docsifyInit = require('../helpers/docsify-init'); + +describe('Vue.js Rendering', function() { + const vueURLs = [ + `${NODE_MODULES_URL}/vue2/dist/vue.js`, + `${NODE_MODULES_URL}/vue3/dist/vue.global.js`, + ]; + + // Tests + // --------------------------------------------------------------------------- + test(`ignores Vue content when window.Vue is not present`, async () => { + await docsifyInit({ + markdown: { + homepage: ` +
test{{ i }}
+ `, + }, + }); + + await page.evaluate(() => { + return 'Vue' in window === false; + }); + await expect(page).toEqualText('#test', 'test{{ i }}'); + }); + + describe('Basic rendering', function() { + for (const vueURL of vueURLs) { + const vueVersion = vueURL.match(/vue(\d+)/)[1]; // vue2|vue3 + + for (const executeScript of ['unspecified', true, false]) { + test(`handles Vue v${vueVersion}.x basic rendering when executeScript is ${executeScript}`, async () => { + const docsifyInitConfig = { + markdown: { + homepage: ` +
test{{ i }}
+ `, + }, + scriptURLs: vueURL, + }; + + if (executeScript !== 'unspecified') { + docsifyInitConfig.config = { + executeScript, + }; + } + + await docsifyInit(docsifyInitConfig); + + await expect(page).toEqualText('#test', 'test12345'); + }); + } + } + }); + + describe('Advanced usage', function() { + const testData = { + vue2: { + markdown: ` +
+ + {{ counter }} +
+ + + `, + }, + vue3: { + markdown: ` +
+ + {{ counter }} +
+ + + `, + }, + }; + + for (const vueURL of vueURLs) { + const vueVersion = vueURL.match(/vue(\d+)/)[1]; // vue2|vue3 + const vueData = testData[`vue${vueVersion}`]; + + for (const executeScript of ['unspecified', true]) { + test(`handles Vue v${vueVersion}.x advanced usage when executeScript is ${executeScript}`, async () => { + const docsifyInitConfig = { + markdown: { + homepage: vueData.markdown, + }, + scriptURLs: vueURL, + }; + + if (executeScript !== 'unspecified') { + docsifyInitConfig.config = { + executeScript, + }; + } + + await docsifyInit(docsifyInitConfig); + + await expect(page).toEqualText('#test span', '0'); + await page.click('#test button'); + await expect(page).toEqualText('#test span', '1'); + }); + } + + test(`handles Vue v${vueVersion}.x advanced usage when executeScript is false`, async () => { + const docsifyInitConfig = { + config: { + executeScript: false, + }, + markdown: { + homepage: vueData.markdown, + }, + scriptURLs: vueURL, + }; + + await docsifyInit(docsifyInitConfig); + + const textContent = await page.textContent('#test span'); + expect(textContent).toBe(''); + }); + } + }); +}); diff --git a/test/fixtures/default/README.md b/test/fixtures/default/README.md deleted file mode 100644 index 28df398a9..000000000 --- a/test/fixtures/default/README.md +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/test/fixtures/simple/README.md b/test/fixtures/simple/README.md deleted file mode 100644 index 0f3fd4699..000000000 --- a/test/fixtures/simple/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Heading - -[another page](other.md) - -## II 1 - -### III 1 - -#### IV 1 - -##### V 1 - - -## II 2 - -### III 2 - -#### IV 2 diff --git a/test/fixtures/simple/other-page.md b/test/fixtures/simple/other-page.md deleted file mode 100644 index 4bc6e9877..000000000 --- a/test/fixtures/simple/other-page.md +++ /dev/null @@ -1,16 +0,0 @@ -# Other - -## two 1 - -### three 1 - -#### four 1 - -##### five 1 - - -## two 2 - -### three 2 - -#### four 2 diff --git a/test/helpers/docsify-init.js b/test/helpers/docsify-init.js new file mode 100644 index 000000000..73637ed69 --- /dev/null +++ b/test/helpers/docsify-init.js @@ -0,0 +1,313 @@ +/* global jestPlaywright page */ +import mock, { proxy } from 'xhr-mock'; +import { waitForSelector } from './wait-for'; + +const axios = require('axios'); +const prettier = require('prettier'); +const stripIndent = require('common-tags/lib/stripIndent'); + +const docsifyPATH = `${LIB_PATH}/docsify.js`; // JSDOM +const docsifyURL = `${LIB_URL}/docsify.js`; // Playwright +const isJSDOM = 'window' in global; +const isPlaywright = 'page' in global; + +/** + * Jest / Playwright helper for creating custom docsify test sites + * + * @param {Object} options options object + * @param {Function|Object} [options.config] docsify configuration (merged with default) + * @param {String} [options.html] HTML content to use for docsify `index.html` page + * @param {Object} [options.markdown] Docsify markdown content + * @param {String} [options.markdown.coverpage] coverpage markdown + * @param {String} [options.markdown.homepage] homepage markdown + * @param {String} [options.markdown.navbar] navbar markdown + * @param {String} [options.markdown.sidebar] sidebar markdown + * @param {Object} [options.routes] custom routes defined as `{ pathOrGlob: responseText }` + * @param {String} [options.script] JS to inject via - - -`; - -/** @type {ReturnType} */ -let server; - -describe('Docsify public API', () => { - before(async () => { - server = http.createServer((request, response) => { - // You pass two more arguments for config and middleware - // More details here: https://github.com/zeit/serve-handler#options - return handler(request, response); - }); - - await new Promise(r => server.listen(port, r)); - }); - - after(async () => { - server.close(err => { - if (err) { - console.error(err); // eslint-disable-line - process.exit(1); - } - // eslint-disable-next-line - console.log('Server closed.'); - }); - }); - - it('global APIs are available', async () => { - // const DOM = new (require('jsdom').JSDOM)(markup, { - const DOM = initJSDOM(markup, { - url: docsifySite, - runScripts: 'dangerously', - resources: 'usable', - }); - - const { documentReady } = require('../../src/core/util/dom'); - await new Promise(resolve => documentReady(resolve, DOM.window.document)); - - // If the script was built successfully for production, then it should load - // and the following APIs should be available: - expect(typeof DOM.window.Docsify).to.equal('object'); - expect(typeof DOM.window.Docsify.util).to.equal('object'); - expect(typeof DOM.window.Docsify.dom).to.equal('object'); - expect(typeof DOM.window.Docsify.get).to.equal('function'); - expect(typeof DOM.window.Docsify.slugify).to.equal('function'); - expect(typeof DOM.window.Docsify.version).to.equal('string'); - expect(typeof DOM.window.DocsifyCompiler).to.equal('function'); - expect(typeof DOM.window.marked).to.equal('function'); - expect(typeof DOM.window.Prism).to.equal('object'); - }); - - describe('Docsify config function', function() { - it('allows $docsify to be a function', async function() { - initJSDOM(markup, { url: docsifySite }); - - window.configFunctionCalled = false; - - window.$docsify = function(vm) { - // Check public API (that which is available at this point) - expect(vm).to.be.an.instanceof(Object); - expect(vm.constructor.name).to.equal('Docsify'); - expect(vm.$fetch).to.be.an.instanceof(Function); - expect(vm.$resetEvents).to.be.an.instanceof(Function); - expect(vm.route).to.be.an.instanceof(Object); - - window.configFunctionCalled = true; - - return {}; - }; - - const { documentReady } = require('../../src/core/util/dom'); - const { Docsify } = require('../../src/core/Docsify'); - await new Promise(resolve => documentReady(resolve)); - - new Docsify(); // eslint-disable-line - - expect(window.configFunctionCalled).to.equal(true); - }); - - it('provides the hooks and vm API to plugins', async function() { - initJSDOM(markup, { url: docsifySite }); - - window.pluginFunctionCalled = false; - - window.$docsify = function(vm) { - const vm1 = vm; - return { - plugins: [ - function(hook, vm2) { - expect(vm1).to.equal(vm2); - - expect(hook.init).to.be.an.instanceof(Function); - expect(hook.beforeEach).to.be.an.instanceof(Function); - expect(hook.afterEach).to.be.an.instanceof(Function); - expect(hook.doneEach).to.be.an.instanceof(Function); - expect(hook.mounted).to.be.an.instanceof(Function); - expect(hook.ready).to.be.an.instanceof(Function); - - window.pluginFunctionCalled = true; - }, - ], - }; - }; - - const { documentReady } = require('../../src/core/util/dom'); - const { Docsify } = require('../../src/core/Docsify'); - await new Promise(resolve => documentReady(resolve)); - - new Docsify(); // eslint-disable-line - - expect(window.pluginFunctionCalled).to.equal(true); - }); - }); -}); diff --git a/test/unit/example.test.js b/test/unit/example.test.js new file mode 100644 index 000000000..224bb10c7 --- /dev/null +++ b/test/unit/example.test.js @@ -0,0 +1,117 @@ +import { greet } from './fixtures/greet.js'; +import { getTimeOfDay } from './fixtures/get-time-of-day.js'; +import * as getTimeOfDayModule from './fixtures/get-time-of-day.js'; + +// Suite +// ----------------------------------------------------------------------------- +describe(`Example Tests`, function() { + // Tests + // --------------------------------------------------------------------------- + describe('Jest & JSDOM basics', function() { + test('dom manipulation (jsdom)', () => { + const testText = 'This is a test'; + const testHTML = `

Test

${testText}

`; + + // Inject HTML + document.body.innerHTML = testHTML; + + // Add class to element and verify + document.body.classList.add('foo'); + + // Test HTML + expect(document.body.getAttribute('class')).toEqual('foo'); + expect(document.body.textContent).toMatch(/Test/); + expect(document.querySelectorAll('p')).toHaveLength(1); + expect(document.querySelector('p').textContent).toBe(testText); + expect(document.querySelector('table')).toBeNull(); + }); + + // Snapshot Testing + // https://jestjs.io/docs/en/snapshot-testing + test('snapshot (jsdom)', () => { + const testText = 'This is a test'; + const testHTML = `

Test

${testText}

`; + + // Inject HTML + document.body.innerHTML = testHTML; + + // Add class to element and verify + document.body.classList.add('foo'); + + const documentHTML = document.documentElement.outerHTML; + + // Test snapshots + expect(documentHTML).toMatchSnapshot(); // See __snapshots__ + expect(documentHTML).toMatchInlineSnapshot( + `"

Test

This is a test

"` + ); + }); + }); + + describe('Fake Timers', function() { + test('data & time', () => { + const fakeDate = new Date().setHours(1); + + jest.useFakeTimers('modern'); + jest.setSystemTime(fakeDate); + + const timeOfDay = getTimeOfDay(); + + expect(timeOfDay).toBe('morning'); + }); + }); + + describe('Mocks & Spys', function() { + test('mock import/require dependency using jest.fn()', () => { + const testModule = require('./fixtures/get-time-of-day.js'); + const { greet: testGreet } = require('./fixtures/greet.js'); + + testModule.getTimeOfDay = jest.fn(() => 'day'); + + const timeOfDay = testModule.getTimeOfDay(); + const greeting = testGreet('John'); + + expect(timeOfDay).toBe('day'); + expect(greeting).toBe(`Good day, John!`); + }); + + test('mock import/require dependency using jest.doMock()', () => { + const mockModulePath = './fixtures/get-time-of-day.js'; + + jest.doMock(mockModulePath, () => ({ + __esModule: true, + getTimeOfDay: jest.fn(() => 'night'), + })); + + const mockGetTimeOfDay = require(mockModulePath).getTimeOfDay; + const { greet: testGreet } = require('./fixtures/greet.js'); + + const timeOfDay = mockGetTimeOfDay(); + const greeting = testGreet('John'); + + expect(timeOfDay).toBe('night'); + expect(greeting).toBe(`Good night, John!`); + }); + + test('spy on native method using jest.spyOn()', () => { + // Replace Math.random() implementation to return fixed value + jest.spyOn(Math, 'random').mockImplementation(() => 0.1); + + expect(Math.random()).toEqual(0.1); + expect(Math.random()).toEqual(0.1); + expect(Math.random()).toEqual(0.1); + }); + + test('spy on import/require dependency using jest.spyOn()', () => { + jest + .spyOn(getTimeOfDayModule, 'getTimeOfDay') + .mockImplementation(() => 'night'); + + const timeOfDay = getTimeOfDay(); + const greeting = greet('John'); + + expect(timeOfDay).toBe('night'); + expect(greeting).toBe(`Good night, John!`); + }); + }); +}); diff --git a/test/unit/fixtures/get-time-of-day.js b/test/unit/fixtures/get-time-of-day.js new file mode 100644 index 000000000..2381e8836 --- /dev/null +++ b/test/unit/fixtures/get-time-of-day.js @@ -0,0 +1,6 @@ +export function getTimeOfDay(hours = new Date().getHours()) { + const timeOfDay = + hours < 12 ? 'morning' : hours < 17 ? 'afternoon' : 'evening'; + + return timeOfDay; +} diff --git a/test/unit/fixtures/greet.js b/test/unit/fixtures/greet.js new file mode 100644 index 000000000..61c58edda --- /dev/null +++ b/test/unit/fixtures/greet.js @@ -0,0 +1,7 @@ +import { getTimeOfDay } from './get-time-of-day'; + +export function greet(name = 'friend') { + const timeOfDay = getTimeOfDay(); + + return `Good ${timeOfDay}, ${name}!`; +} diff --git a/test/unit/render-util.test.js b/test/unit/render-util.test.js new file mode 100644 index 000000000..3a82a0f9d --- /dev/null +++ b/test/unit/render-util.test.js @@ -0,0 +1,15 @@ +const { removeAtag } = require(`${SRC_PATH}/core/render/utils`); + +// Suite +// ----------------------------------------------------------------------------- +describe('core/render/utils', () => { + // removeAtag() + // --------------------------------------------------------------------------- + describe('removeAtag()', () => { + test('removeAtag from a link', () => { + const result = removeAtag('content'); + + expect(result).toEqual('content'); + }); + }); +}); diff --git a/test/unit/render.test.js b/test/unit/render.test.js deleted file mode 100644 index 28e88ac0e..000000000 --- a/test/unit/render.test.js +++ /dev/null @@ -1,330 +0,0 @@ -const { expect } = require('chai'); -const { init, expectSameDom } = require('../_helper'); - -describe('render', function() { - it('important content (tips)', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile('!> **Time** is money, my friend!'); - expect(output).equal( - '

Time is money, my friend!

' - ); - }); - - describe('lists', function() { - it('as unordered task list', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile(` - - [x] Task 1 - - [ ] Task 2 - - [ ] Task 3`); - expect( - output, - `
    -
  • -
  • -
  • -
` - ); - }); - - it('as ordered task list', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile(` - 1. [ ] Task 1 - 2. [x] Task 2`); - expectSameDom( - output, - `
    -
  1. -
  2. -
` - ); - }); - - it('normal unordered', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile(` - - [linktext](link) - - just text`); - expectSameDom( - output, - `` - ); - }); - - it('unordered with custom start', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile(` - 1. first - 2. second - - text - - 3. third`); - expectSameDom( - output, - `
  1. first

  2. second

    text

  3. third

` - ); - }); - - it('nested', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile(` - - 1 - - 2 - - 2 a - - 2 b - - 3`); - expectSameDom( - output, - `
    -
  • 1
  • -
  • 2
      -
    • 2 a
    • -
    • 2 b
    • -
    -
  • -
  • 3
  • -
` - ); - }); - }); - - describe('image', function() { - it('regular', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile('![alt text](http://imageUrl)'); - - expectSameDom( - output, - '

alt text

' - ); - }); - - it('class', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile( - "![alt text](http://imageUrl ':class=someCssClass')" - ); - - expectSameDom( - output, - '

alt text

' - ); - }); - - it('id', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile( - "![alt text](http://imageUrl ':id=someCssID')" - ); - - expectSameDom( - output, - '

alt text

' - ); - }); - - it('no-zoom', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile( - "![alt text](http://imageUrl ':no-zoom')" - ); - - expectSameDom( - output, - '

alt text

' - ); - }); - - describe('size', function() { - it('width and height', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile( - "![alt text](http://imageUrl ':size=WIDTHxHEIGHT')" - ); - - expectSameDom( - output, - '

alt text

' - ); - }); - - it('width', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile( - "![alt text](http://imageUrl ':size=50')" - ); - - expectSameDom( - output, - '

alt text

' - ); - }); - }); - }); - - describe('heading', function() { - it('h1', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile('# h1 tag'); - expectSameDom( - output, - ` -

- - h1 tag - -

` - ); - }); - - it('h2', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile('## h2 tag'); - expectSameDom( - output, - ` -

- - h2 tag - -

` - ); - }); - - it('h3', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile('### h3 tag'); - expectSameDom( - output, - ` -

- - h3 tag - -

` - ); - }); - - it('h4', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile('#### h4 tag'); - expectSameDom( - output, - ` -

- - h4 tag - -

` - ); - }); - - it('h5', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile('##### h5 tag'); - expectSameDom( - output, - ` -
- - h5 tag - -
` - ); - }); - - it('h6', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile('###### h6 tag'); - expectSameDom( - output, - ` -
- - h6 tag - -
` - ); - }); - }); - - describe('link', function() { - it('regular', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile('[alt text](http://url)'); - - expectSameDom( - output, - '

alt text

' - ); - }); - - it('linkrel', async function() { - const { docsify } = await init('default', { - externalLinkTarget: '_blank', - externalLinkRel: 'noopener', - }); - const output = docsify.compiler.compile( - '[alt text](http://www.example.com)' - ); - - expectSameDom( - output, - '

alt text

' - ); - }); - - it('disabled', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile( - "[alt text](http://url ':disabled')" - ); - - expectSameDom( - output, - '

alt text

' - ); - }); - - it('target', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile( - "[alt text](http://url ':target=_self')" - ); - - expectSameDom( - output, - '

alt text

' - ); - }); - - it('class', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile( - "[alt text](http://url ':class=someCssClass')" - ); - - expectSameDom( - output, - '

alt text

' - ); - }); - - it('id', async function() { - const { docsify } = await init(); - const output = docsify.compiler.compile( - "[alt text](http://url ':id=someCssID')" - ); - - expectSameDom( - output, - '

alt text

' - ); - }); - }); -}); diff --git a/test/unit/router-history-base.test.js b/test/unit/router-history-base.test.js new file mode 100644 index 000000000..309286cb0 --- /dev/null +++ b/test/unit/router-history-base.test.js @@ -0,0 +1,69 @@ +const { History } = require(`${SRC_PATH}/core/router/history/base`); + +class MockHistory extends History { + parse(path) { + return { path }; + } +} + +// Suite +// ----------------------------------------------------------------------------- +describe('router/history/base', () => { + // Setup & Teardown + // --------------------------------------------------------------------------- + let history; + + // resolvePath: true + // --------------------------------------------------------------------------- + describe('relativePath: true', () => { + // Setup & Teardown + // ------------------------------------------------------------------------- + beforeEach(() => { + history = new MockHistory({ relativePath: true }); + }); + + // Tests + // ------------------------------------------------------------------------- + test('toURL', () => { + const url = history.toURL('guide.md', {}, '/zh-ch/'); + + expect(url).toEqual('/zh-ch/guide'); + }); + + test('toURL with double dot', () => { + const url = history.toURL('../README.md', {}, '/zh-ch/'); + + expect(url).toEqual('/README'); + }); + + test('toURL child path', () => { + const url = history.toURL('config/example.md', {}, '/zh-ch/'); + + expect(url).toEqual('/zh-ch/config/example'); + }); + + test('toURL absolute path', () => { + const url = history.toURL('/README', {}, '/zh-ch/'); + + expect(url).toEqual('/README'); + }); + }); + + // resolvePath: false + // --------------------------------------------------------------------------- + describe('relativePath: false', () => { + // Setup & Teardown + // ------------------------------------------------------------------------- + beforeEach(() => { + history = new MockHistory({ relativePath: false }); + }); + + // Tests + // ------------------------------------------------------------------------- + test('toURL', () => { + const url = history.toURL('README', {}, '/zh-ch/'); + + expect(url).toEqual('/README'); + }); + }); +}); diff --git a/test/unit/router-util.test.js b/test/unit/router-util.test.js new file mode 100644 index 000000000..d359b2d31 --- /dev/null +++ b/test/unit/router-util.test.js @@ -0,0 +1,27 @@ +const { resolvePath } = require(`${SRC_PATH}/core/util`); + +// Suite +// ----------------------------------------------------------------------------- +describe('router/util', () => { + // resolvePath() + // --------------------------------------------------------------------------- + describe('resolvePath()', () => { + test('resolvePath with filename', () => { + const result = resolvePath('hello.md'); + + expect(result).toEqual('/hello.md'); + }); + + test('resolvePath with ./', () => { + const result = resolvePath('./hello.md'); + + expect(result).toEqual('/hello.md'); + }); + + test('resolvePath with ../', () => { + const result = resolvePath('test/../hello.md'); + + expect(result).toEqual('/hello.md'); + }); + }); +}); diff --git a/test/unit/util.test.js b/test/unit/util.test.js deleted file mode 100644 index 9dadf28a3..000000000 --- a/test/unit/util.test.js +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable no-global-assign */ -require = require('esm')( - module /* , options */ -); /* eslint-disable-line no-global-assign */ -const { expect } = require('chai'); -const { resolvePath } = require('../../src/core/router/util'); - -describe('router/util', function() { - it('resolvePath', async function() { - // WHEN - const result = resolvePath('hello.md'); - - // THEN - expect(result).equal('/hello.md'); - }); - - it('resolvePath with dot', async function() { - // WHEN - const result = resolvePath('./hello.md'); - - // THEN - expect(result).equal('/hello.md'); - }); - - it('resolvePath with two dots', async function() { - // WHEN - const result = resolvePath('test/../hello.md'); - - // THEN - expect(result).equal('/hello.md'); - }); -});