refactor: Update test environments and lint configuration (#1736)
* Update test environments and lint configuration Update Jest (unit + integration) and Playwright (e2e) test environments. Includes stability improvements for e2e tests using newer, more stable methods per the Playwright docs. - Update Jest 26 => 27 - Update Jest-related libs (babel parser) - Update Playwright 1.8 => Playwright Test 1.18 - Update GitHub CI (action versions, job parallelization, and matrices) - Update ESLint 5 => 8 - Update ESLint-related libs (parser, prettier, Jest, Playwright) - Fix test failures on M1-based Macs - Fix e2e stability issues by replacing PW $ method calls - Fix ESLint errors - Fix incorrect CI flag on Jest runs (-ci => --ci) - Refactor e2e test runner from Jest to Playwright Test - Refactor e2e test files for Playwright Test - Refactor fix-lint script name to lint:fix for consistency - Refactor npm scripts order for readability - Remove unnecessary configs and libs - Remove example image snapshots
|
@ -1,10 +1,9 @@
|
|||
.git
|
||||
packages/docsify-server-renderer/build.js
|
||||
node_modules
|
||||
build
|
||||
server.js
|
||||
lib
|
||||
themes
|
||||
build
|
||||
docs/
|
||||
**/*.md
|
||||
build
|
||||
docs
|
||||
lib
|
||||
node_modules
|
||||
packages/docsify-server-renderer/build.js
|
||||
server.js
|
||||
themes
|
||||
|
|
34
.eslintrc.js
|
@ -1,24 +1,28 @@
|
|||
const prettierConfig = require('./.prettierrc');
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: 'babel-eslint',
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:import/recommended',
|
||||
'plugin:prettier/recommended', // Must be last
|
||||
],
|
||||
parser: '@babel/eslint-parser',
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2019,
|
||||
},
|
||||
plugins: ['prettier', 'import'],
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
es6: true,
|
||||
node: true,
|
||||
},
|
||||
plugins: ['prettier', 'import'],
|
||||
extends: ['eslint:recommended', 'plugin:import/recommended'],
|
||||
settings: {
|
||||
'import/ignore': ['node_modules', '.json$'],
|
||||
},
|
||||
rules: {
|
||||
'prettier/prettier': ['error'],
|
||||
camelcase: ['warn'],
|
||||
'no-useless-escape': ['warn'],
|
||||
curly: ['error', 'all'],
|
||||
'dot-notation': ['error'],
|
||||
eqeqeq: ['error'],
|
||||
|
@ -33,9 +37,16 @@ module.exports = {
|
|||
'no-proto': ['error'],
|
||||
'no-return-assign': ['error'],
|
||||
'no-self-compare': ['error'],
|
||||
'no-shadow': ['warn'],
|
||||
'no-shadow-restricted-names': ['error'],
|
||||
'no-shadow': [
|
||||
'error',
|
||||
{
|
||||
allow: ['Events', 'Fetch', 'Lifecycle', 'Render', 'Router'],
|
||||
},
|
||||
],
|
||||
'no-unused-vars': ['error', { args: 'none' }],
|
||||
'no-useless-call': ['error'],
|
||||
'no-useless-escape': ['warn'],
|
||||
'no-var': ['error'],
|
||||
'no-void': ['error'],
|
||||
'no-with': ['error'],
|
||||
|
@ -46,18 +57,21 @@ module.exports = {
|
|||
|
||||
// Import rules
|
||||
// Search way how integrate with `lerna`
|
||||
'import/no-unresolved': 'off',
|
||||
'import/imports-first': ['error'],
|
||||
'import/newline-after-import': ['error'],
|
||||
'import/no-duplicates': ['error'],
|
||||
'import/no-mutable-exports': ['error'],
|
||||
'import/no-named-as-default': ['error'],
|
||||
'import/no-named-as-default-member': ['error'],
|
||||
'import/no-named-as-default': ['error'],
|
||||
'import/no-unresolved': 'off',
|
||||
'import/order': ['warn'],
|
||||
|
||||
// Prettier (Must be last)
|
||||
'prettier/prettier': ['warn', prettierConfig],
|
||||
},
|
||||
globals: {
|
||||
Docsify: 'writable',
|
||||
$docsify: 'writable',
|
||||
Docsify: 'writable',
|
||||
dom: 'writable',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
name: Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [12.x, 14.x]
|
||||
|
||||
steps:
|
||||
- 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
|
|
@ -2,41 +2,78 @@ name: Build & Test
|
|||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
branches: [master, develop]
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
branches: [master, develop]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: ['lts/*']
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- name: Install dependencies
|
||||
run: npm ci --ignore-scripts
|
||||
- name: Build
|
||||
run: npm run build
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
|
||||
test-jest:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [12.x, 14.x]
|
||||
node-version: ['lts/*']
|
||||
os: ['macos-latest', 'ubuntu-latest', 'windows-latest']
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
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
|
||||
- name: e2e tests
|
||||
run: npm run test:e2e -- --ci --runInBand
|
||||
- name: Upload artifacts (diff output)
|
||||
cache: 'npm'
|
||||
- name: Install dependencies
|
||||
run: npm ci --ignore-scripts
|
||||
- name: Build
|
||||
run: npm run build
|
||||
- name: Unit Tests
|
||||
run: npm run test:unit -- --ci --runInBand
|
||||
- name: Integration Tests
|
||||
run: npm run test:integration -- --ci --runInBand
|
||||
|
||||
test-playwright:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: ['lts/*']
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- name: Install dependencies
|
||||
run: npm ci --ignore-scripts
|
||||
- name: Build
|
||||
run: npm run build
|
||||
- name: Install Playwright
|
||||
run: npx playwright install --with-deps
|
||||
- name: E2E Tests (Playwright)
|
||||
run: npm run test:e2e
|
||||
- name: Store artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: ${{ matrix.os }}-${{ matrix.node-version }}-diff-output
|
||||
path: ${{ github.workspace }}/test/**/__diff_output__/*
|
||||
name: ${{ matrix.os }}-${{ matrix.node-version }}-artifacts
|
||||
path: |
|
||||
_playwright-results/
|
||||
_playwright-report/
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
*.log
|
||||
.DS_Store
|
||||
.idea
|
||||
__diff_output__
|
||||
lib/
|
||||
*.log
|
||||
_playwright-report
|
||||
_playwright-results
|
||||
lib
|
||||
node_modules
|
||||
themes/
|
||||
themes
|
||||
|
||||
# exceptions
|
||||
!.gitkeep
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.eslintignore
|
||||
.eslintrc
|
||||
.github/
|
||||
.github
|
||||
.gitignore
|
||||
.travis.yml
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module.exports = {
|
||||
arrowParens: 'avoid',
|
||||
singleQuote: true,
|
||||
trailingComma: 'es5',
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
{
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"cSpell.words": ["coverpage"]
|
||||
}
|
||||
|
|
|
@ -2,60 +2,28 @@ const { TEST_HOST } = require('./test/config/server.js');
|
|||
|
||||
const sharedConfig = {
|
||||
errorOnDeprecated: true,
|
||||
globals: {
|
||||
TEST_HOST,
|
||||
},
|
||||
globalSetup: './test/config/jest.setup.js',
|
||||
globalTeardown: './test/config/jest.teardown.js',
|
||||
resetModules: true,
|
||||
restoreMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/test/config/jest.setup-tests.js'],
|
||||
testEnvironment: 'jsdom',
|
||||
testURL: `${TEST_HOST}/_blank.html`,
|
||||
};
|
||||
|
||||
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)
|
||||
// Unit Tests
|
||||
{
|
||||
...sharedConfig,
|
||||
displayName: 'unit',
|
||||
setupFilesAfterEnv: ['<rootDir>/test/config/jest.setup-tests.js'],
|
||||
...sharedConfig,
|
||||
testMatch: ['<rootDir>/test/unit/*.test.js'],
|
||||
testURL: `${TEST_HOST}/_blank.html`,
|
||||
},
|
||||
// Integration Tests (Jest)
|
||||
// Integration Tests
|
||||
{
|
||||
...sharedConfig,
|
||||
displayName: 'integration',
|
||||
setupFilesAfterEnv: ['<rootDir>/test/config/jest.setup-tests.js'],
|
||||
testMatch: ['<rootDir>/test/integration/*.test.js'],
|
||||
testURL: `${TEST_HOST}/_blank.html`,
|
||||
},
|
||||
// E2E Tests (Jest + Playwright)
|
||||
{
|
||||
...sharedConfig,
|
||||
displayName: 'e2e',
|
||||
preset: 'jest-playwright-preset',
|
||||
setupFilesAfterEnv: [
|
||||
'<rootDir>/test/config/jest-playwright.setup-tests.js',
|
||||
],
|
||||
testEnvironmentOptions: {
|
||||
'jest-playwright': {
|
||||
// prettier-ignore
|
||||
browsers: [
|
||||
'chromium',
|
||||
'firefox',
|
||||
'webkit',
|
||||
],
|
||||
launchOptions: {
|
||||
// headless: false,
|
||||
// devtools: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
testMatch: ['<rootDir>/test/e2e/*.test.js'],
|
||||
testMatch: ['<rootDir>/test/integration/*.test.js'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
65
package.json
|
@ -21,39 +21,39 @@
|
|||
],
|
||||
"scripts": {
|
||||
"bootstrap": "npm i && lerna bootstrap && npm run build:ssr",
|
||||
"serve": "node server",
|
||||
"serve:ssr": "cross-env SSR=1 node server",
|
||||
"dev": "run-p serve watch:*",
|
||||
"dev:ssr": "run-p serve:ssr watch:*",
|
||||
"lint": "eslint .",
|
||||
"fixlint": "eslint . --fix",
|
||||
"test": "jest",
|
||||
"build:test": "npm run build && npm test",
|
||||
"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",
|
||||
"build:cover": "node build/cover.js",
|
||||
"build:css:min": "mkdirp lib/themes && npm run css -- -o lib/themes && node build/mincss.js",
|
||||
"build:css": "mkdirp themes && npm run css -- -o themes",
|
||||
"build:js": "cross-env NODE_ENV=production node build/build.js",
|
||||
"build:ssr": "node build/ssr.js",
|
||||
"build:cover": "node build/cover.js",
|
||||
"build:test": "npm run build && npm test",
|
||||
"build": "rimraf lib themes && run-s build:js build:css build:css:min build:ssr build:cover",
|
||||
"prepare": "npm run build",
|
||||
"pub:next": "cross-env RELEASE_TAG=next sh build/release.sh",
|
||||
"pub": "sh build/release.sh",
|
||||
"postinstall": "opencollective-postinstall",
|
||||
"css": "node build/css",
|
||||
"dev:ssr": "run-p serve:ssr watch:*",
|
||||
"dev": "run-p serve watch:*",
|
||||
"docker:build:test": "npm run docker:cli -- build:test",
|
||||
"docker:build": "docker build -f Dockerfile -t docsify-test:local .",
|
||||
"docker:clean": "docker rmi docsify-test:local",
|
||||
"docker:cli": "docker run --rm -it --ipc=host --mount type=bind,source=$(pwd)/test,target=/app/test docsify-test:local",
|
||||
"docker:rebuild": "npm run docker:clean && npm run docker:build",
|
||||
"docker:test": "npm run docker:cli -- test",
|
||||
"docker:build:test": "npm run docker:cli -- build:test",
|
||||
"docker:test:e2e": "npm run docker:cli -- test:e2e",
|
||||
"docker:test:integration": "npm run docker:cli -- test:integration",
|
||||
"docker:test:unit": "npm run docker:cli -- test:unit",
|
||||
"docker:cli": "docker run --rm -it --ipc=host --mount type=bind,source=$(pwd)/test,target=/app/test docsify-test:local"
|
||||
"docker:test": "npm run docker:cli -- test",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"lint": "eslint .",
|
||||
"postinstall": "opencollective-postinstall",
|
||||
"prepare": "npm run build",
|
||||
"pub:next": "cross-env RELEASE_TAG=next sh build/release.sh",
|
||||
"pub": "sh build/release.sh",
|
||||
"serve:ssr": "cross-env SSR=1 node server",
|
||||
"serve": "node server",
|
||||
"test:e2e": "playwright test",
|
||||
"test:integration": "jest --selectProjects integration",
|
||||
"test:unit": "jest --selectProjects unit",
|
||||
"test": "jest && run-s test:e2e",
|
||||
"watch:css": "npm run css -- -o themes -w",
|
||||
"watch:js": "node build/build.js"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
|
@ -75,11 +75,12 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.11.6",
|
||||
"@babel/eslint-parser": "^7.16.5",
|
||||
"@babel/preset-env": "^7.11.5",
|
||||
"@playwright/test": "^1.18.1",
|
||||
"autoprefixer-stylus": "^1.0.0",
|
||||
"axios": "^0.21.1",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"babel-jest": "^26.3.0",
|
||||
"babel-jest": "^27.4.6",
|
||||
"browser-sync": "^2.26.12",
|
||||
"chokidar": "^3.4.2",
|
||||
"common-tags": "^1.8.0",
|
||||
|
@ -87,22 +88,20 @@
|
|||
"copy-dir": "^1.2.0",
|
||||
"cross-env": "^6.0.3",
|
||||
"cssnano": "^4.1.10",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint": "^8.7.0",
|
||||
"eslint-config-prettier": "^8.3.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",
|
||||
"eslint-plugin-jest": "^26.0.0",
|
||||
"eslint-plugin-playwright": "^0.8.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"husky": "^3.1.0",
|
||||
"jest": "^26.4.2",
|
||||
"jest-image-snapshot": "^4.2.0",
|
||||
"jest-playwright-preset": "^1.4.1",
|
||||
"jest": "^27.4.7",
|
||||
"lerna": "^3.22.1",
|
||||
"lint-staged": "^10.4.0",
|
||||
"live-server": "^1.2.1",
|
||||
"mkdirp": "^0.5.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"playwright": "^1.8.0",
|
||||
"prettier": "^1.19.1",
|
||||
"prettier": "^2.5.1",
|
||||
"rimraf": "^3.0.0",
|
||||
"rollup": "^1.23.1",
|
||||
"rollup-plugin-async": "^1.2.0",
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
const { devices } = require('@playwright/test');
|
||||
|
||||
/**
|
||||
* @see https://playwright.dev/docs/test-configuration
|
||||
* @type {import('@playwright/test').PlaywrightTestConfig}
|
||||
*/
|
||||
const config = {
|
||||
// Setup / Teardown
|
||||
globalSetup: './test/config/playwright.setup.js',
|
||||
globalTeardown: './test/config/playwright.teardown.js',
|
||||
|
||||
// Test Execution
|
||||
expect: {
|
||||
timeout: 5000,
|
||||
},
|
||||
retries: process.env.CI ? 2 : 0, // Retry on CI only
|
||||
testDir: './test/e2e',
|
||||
timeout: 30 * 1000,
|
||||
workers: process.env.CI ? 1 : undefined, // No parallel tests on CI
|
||||
forbidOnly: !!process.env.CI, // Fail on CI if test.only in source
|
||||
|
||||
// Output
|
||||
outputDir: './_playwright-results/', // screenshots, videos, traces, etc.
|
||||
reporter: [
|
||||
[
|
||||
'html',
|
||||
{
|
||||
open: 'never',
|
||||
outputFolder: '_playwright-report',
|
||||
},
|
||||
],
|
||||
],
|
||||
snapshotDir: './test/e2e/__snapshots__',
|
||||
|
||||
// Config - Shared
|
||||
// See https://playwright.dev/docs/api/class-testoptions
|
||||
use: {
|
||||
actionTimeout: 0,
|
||||
baseURL: `${process.env.TEST_HOST}`, // Allow relative page.goto() (e.g. `await page.goto('/')`).
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
|
||||
// Projects
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
{
|
||||
name: 'firefox',
|
||||
use: { ...devices['Desktop Firefox'] },
|
||||
},
|
||||
{
|
||||
name: 'webkit',
|
||||
use: { ...devices['Desktop Safari'] },
|
||||
},
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] }
|
||||
// },
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = config;
|
|
@ -3,7 +3,7 @@ import { merge, hyphenate, isPrimitive, hasOwn } from './util/core';
|
|||
const currentScript = document.currentScript;
|
||||
|
||||
/** @param {import('./Docsify').Docsify} vm */
|
||||
export default function(vm) {
|
||||
export default function (vm) {
|
||||
const config = merge(
|
||||
{
|
||||
el: '#app',
|
||||
|
|
|
@ -13,7 +13,7 @@ const cache = {};
|
|||
*/
|
||||
export function get(url, hasBar = false, headers = {}) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
const on = function() {
|
||||
const on = function () {
|
||||
xhr.addEventListener.apply(xhr, arguments);
|
||||
};
|
||||
|
||||
|
@ -33,7 +33,7 @@ export function get(url, hasBar = false, headers = {}) {
|
|||
xhr.send();
|
||||
|
||||
return {
|
||||
then: function(success, error = noop) {
|
||||
then: function (success, error = noop) {
|
||||
if (hasBar) {
|
||||
const id = setInterval(
|
||||
_ =>
|
||||
|
|
|
@ -152,11 +152,9 @@ export function Fetch(Base) {
|
|||
if (path) {
|
||||
path = this.router.getFile(root + path);
|
||||
this.coverIsHTML = /\.html$/g.test(path);
|
||||
get(
|
||||
path + stringifyQuery(query, ['id']),
|
||||
false,
|
||||
requestHeaders
|
||||
).then(text => this._renderCover(text, coverOnly));
|
||||
get(path + stringifyQuery(query, ['id']), false, requestHeaders).then(
|
||||
text => this._renderCover(text, coverOnly)
|
||||
);
|
||||
} else {
|
||||
this._renderCover(null, coverOnly);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import { get } from './fetch/ajax';
|
|||
// major release. We'll tell people to get everything from the DOCSIFY global
|
||||
// when using the global build, but we'll highly recommend for them to import
|
||||
// from the ESM build (f.e. lib/docsify.esm.js and lib/docsify.min.esm.js).
|
||||
export default function() {
|
||||
export default function () {
|
||||
window.Docsify = {
|
||||
util,
|
||||
dom,
|
||||
|
|
|
@ -30,7 +30,7 @@ export function Lifecycle(Base) {
|
|||
callHook(hookName, data, next = noop) {
|
||||
const queue = this._hooks[hookName];
|
||||
|
||||
const step = function(index) {
|
||||
const step = function (index) {
|
||||
const hookFn = queue[index];
|
||||
|
||||
if (index >= queue.length) {
|
||||
|
|
|
@ -28,8 +28,9 @@ const compileMedia = {
|
|||
},
|
||||
iframe(url, title) {
|
||||
return {
|
||||
html: `<iframe src="${url}" ${title ||
|
||||
'width=100% height=400'}></iframe>`,
|
||||
html: `<iframe src="${url}" ${
|
||||
title || 'width=100% height=400'
|
||||
}></iframe>`,
|
||||
};
|
||||
},
|
||||
video(url, title) {
|
||||
|
@ -204,7 +205,7 @@ export class Compiler {
|
|||
* @param {Number} level Type of heading (h<level> tag)
|
||||
* @returns {String} Heading element
|
||||
*/
|
||||
origin.heading = renderer.heading = function(text, level) {
|
||||
origin.heading = renderer.heading = function (text, level) {
|
||||
let { str, config } = getAndRemoveConfig(text);
|
||||
const nextToc = { level, title: removeAtag(str) };
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import Prism from 'prismjs';
|
|||
import 'prismjs/components/prism-markup-templating';
|
||||
|
||||
export const highlightCodeCompiler = ({ renderer }) =>
|
||||
(renderer.code = function(code, lang = 'markup') {
|
||||
(renderer.code = function (code, lang = 'markup') {
|
||||
const langOrMarkup = Prism.languages[lang] || Prism.languages.markup;
|
||||
const text = Prism.highlight(
|
||||
code.replace(/@DOCSIFY_QM@/g, '`'),
|
||||
|
|
|
@ -15,7 +15,7 @@ function walkFetchEmbed({ embedTokens, compile, fetch }, cb) {
|
|||
|
||||
while ((token = embedTokens[step++])) {
|
||||
// eslint-disable-next-line no-shadow
|
||||
const next = (function(token) {
|
||||
const next = (function (token) {
|
||||
return text => {
|
||||
let embedToken;
|
||||
if (text) {
|
||||
|
|
|
@ -15,6 +15,6 @@ export function emojify(text) {
|
|||
.replace(/<(pre|template|code)[^>]*?>[\s\S]+?<\/(pre|template|code)>/g, m =>
|
||||
m.replace(/:/g, '__colon__')
|
||||
)
|
||||
.replace(/:([a-z0-9_\-\+]+?):/g, (inBrowser && window.emojify) || replace)
|
||||
.replace(/:([a-z0-9_\-+]+?):/g, (inBrowser && window.emojify) || replace)
|
||||
.replace(/__colon__/g, ':');
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ function renderMain(html) {
|
|||
// This provides a global store for all Vue instances that receive
|
||||
// vueGlobalOptions as their configuration.
|
||||
if (vueGlobalData) {
|
||||
vueConfig.data = function() {
|
||||
vueConfig.data = function () {
|
||||
return vueGlobalData;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ function init() {
|
|||
/**
|
||||
* Render progress bar
|
||||
*/
|
||||
export default function({ loaded, total, step }) {
|
||||
export default function ({ loaded, total, step }) {
|
||||
let num;
|
||||
|
||||
!barEl && init();
|
||||
|
|
|
@ -32,6 +32,6 @@ export function slugify(str) {
|
|||
return slug;
|
||||
}
|
||||
|
||||
slugify.clear = function() {
|
||||
slugify.clear = function () {
|
||||
cache = {};
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@ export function parseQuery(query) {
|
|||
}
|
||||
|
||||
// Simple parse
|
||||
query.split('&').forEach(function(param) {
|
||||
query.split('&').forEach(function (param) {
|
||||
const parts = param.replace(/\+/g, ' ').split('=');
|
||||
|
||||
res[parts[0]] = parts[1] && decode(parts[1]);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
export function cached(fn) {
|
||||
const cache = Object.create(null);
|
||||
return function(str) {
|
||||
return function (str) {
|
||||
const key = isPrimitive(str) ? str : JSON.stringify(str);
|
||||
const hit = cache[key];
|
||||
return hit || (cache[key] = fn(str));
|
||||
|
@ -29,7 +29,7 @@ export const hasOwn = Object.prototype.hasOwnProperty;
|
|||
*/
|
||||
export const merge =
|
||||
Object.assign ||
|
||||
function(to) {
|
||||
function (to) {
|
||||
for (let i = 1; i < arguments.length; i++) {
|
||||
const from = Object(arguments[i]);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ export const isMobile = inBrowser && document.body.clientWidth <= 600;
|
|||
*/
|
||||
export const supportsPushState =
|
||||
inBrowser &&
|
||||
(function() {
|
||||
(function () {
|
||||
// Borrowed wholesale from https://github.com/defunkt/jquery-pjax
|
||||
return (
|
||||
window.history &&
|
||||
|
|
|
@ -8,7 +8,7 @@ function replaceVar(block, color) {
|
|||
);
|
||||
}
|
||||
|
||||
export default function(color) {
|
||||
export default function (color) {
|
||||
// Variable support
|
||||
if (window.CSS && window.CSS.supports && window.CSS.supports('(--v:red)')) {
|
||||
return;
|
||||
|
|
|
@ -39,7 +39,7 @@ function install(hook, vm) {
|
|||
if (typeof window.DISQUS !== 'undefined') {
|
||||
window.DISQUS.reset({
|
||||
reload: true,
|
||||
config: function() {
|
||||
config: function () {
|
||||
this.page.url = location.origin + '/-' + vm.route.path;
|
||||
this.page.identifier = vm.route.path;
|
||||
this.page.title = document.title;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable camelcase */
|
||||
const AllGithubEmoji = {
|
||||
'100': 'unicode/1f4af',
|
||||
'1234': 'unicode/1f522',
|
||||
100: 'unicode/1f4af',
|
||||
1234: 'unicode/1f522',
|
||||
'+1': 'unicode/1f44d',
|
||||
'-1': 'unicode/1f44e',
|
||||
'1st_place_medal': 'unicode/1f947',
|
||||
|
@ -1804,8 +1804,8 @@ const AllGithubEmoji = {
|
|||
|
||||
// Emoji from GitHub API
|
||||
// https://api.github.com/emojis
|
||||
window.emojify = function(match, $1) {
|
||||
return AllGithubEmoji.hasOwnProperty($1) === false
|
||||
window.emojify = function (match, $1) {
|
||||
return Object.prototype.hasOwnProperty.call(AllGithubEmoji, $1) === false
|
||||
? match
|
||||
: '<img class="emoji" src="https://github.githubassets.com/images/icons/emoji/' +
|
||||
AllGithubEmoji[$1] +
|
||||
|
|
|
@ -18,7 +18,7 @@ function handleExternalScript() {
|
|||
}
|
||||
}
|
||||
|
||||
const install = function(hook) {
|
||||
const install = function (hook) {
|
||||
hook.doneEach(handleExternalScript);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import parser from './parser';
|
||||
|
||||
const install = function(hook, vm) {
|
||||
const install = function (hook, vm) {
|
||||
// Used to remove front matter from embedded pages if installed.
|
||||
vm.config.frontMatter = {};
|
||||
vm.config.frontMatter.installed = true;
|
||||
vm.config.frontMatter.parseMarkdown = function(content) {
|
||||
vm.config.frontMatter.parseMarkdown = function (content) {
|
||||
const { body } = parser(content);
|
||||
return body;
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ function init(id) {
|
|||
appendScript();
|
||||
window.ga =
|
||||
window.ga ||
|
||||
function() {
|
||||
function () {
|
||||
(window.ga.q = window.ga.q || []).push(arguments);
|
||||
};
|
||||
|
||||
|
@ -28,7 +28,7 @@ function collect() {
|
|||
window.ga('send', 'pageview');
|
||||
}
|
||||
|
||||
const install = function(hook) {
|
||||
const install = function (hook) {
|
||||
if (!$docsify.ga) {
|
||||
console.error('[Docsify] ga is required.');
|
||||
return;
|
||||
|
|
|
@ -9,7 +9,7 @@ function init(options) {
|
|||
window._paq = window._paq || [];
|
||||
window._paq.push(['trackPageView']);
|
||||
window._paq.push(['enableLinkTracking']);
|
||||
setTimeout(function() {
|
||||
setTimeout(function () {
|
||||
appendScript(options);
|
||||
window._paq.push(['setTrackerUrl', options.host + '/matomo.php']);
|
||||
window._paq.push(['setSiteId', String(options.id)]);
|
||||
|
@ -26,7 +26,7 @@ function collect() {
|
|||
window._paq.push(['trackPageView']);
|
||||
}
|
||||
|
||||
const install = function(hook) {
|
||||
const install = function (hook) {
|
||||
if (!$docsify.matomo) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('[Docsify] matomo is required.');
|
||||
|
|
|
@ -13,7 +13,7 @@ const CONFIG = {
|
|||
pathNamespaces: undefined,
|
||||
};
|
||||
|
||||
const install = function(hook, vm) {
|
||||
const install = function (hook, vm) {
|
||||
const { util } = Docsify;
|
||||
const opts = vm.config.search || CONFIG;
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ function getTableData(token) {
|
|||
if (!token.text && token.type === 'table') {
|
||||
token.cells.unshift(token.header);
|
||||
token.text = token.cells
|
||||
.map(function(rows) {
|
||||
.map(function (rows) {
|
||||
return rows.join(' | ');
|
||||
})
|
||||
.join(' |\n ');
|
||||
|
@ -85,7 +85,7 @@ export function genIndex(path, content = '', router, depth) {
|
|||
let slug;
|
||||
let title = '';
|
||||
|
||||
tokens.forEach(function(token, tokenIndex) {
|
||||
tokens.forEach(function (token, tokenIndex) {
|
||||
if (token.type === 'heading' && token.depth <= depth) {
|
||||
const { str, config } = getAndRemoveConfig(token.text);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
## Global Variables
|
||||
|
||||
- `TEST_HOST`: Test server ip:port
|
||||
- `process.env.TEST_HOST`: Test server ip:port
|
||||
|
||||
## CLI commands
|
||||
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/* global browserName page */
|
||||
const { configureToMatchImageSnapshot } = require('jest-image-snapshot');
|
||||
|
||||
// Lifecycle Hooks
|
||||
// -----------------------------------------------------------------------------
|
||||
beforeAll(async () => {
|
||||
// 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.resetContext();
|
||||
|
||||
// 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(`${TEST_HOST}/_blank.html`);
|
||||
});
|
|
@ -1,3 +1,5 @@
|
|||
/* global afterEach, beforeAll, beforeEach */
|
||||
|
||||
import mock from 'xhr-mock';
|
||||
|
||||
const sideEffects = {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
const server = require('./server.js');
|
||||
|
||||
module.exports = async config => {
|
||||
await server.startAsync();
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
const server = require('./server.js');
|
||||
|
||||
module.exports = async config => {
|
||||
server.stop();
|
||||
};
|
|
@ -2,10 +2,9 @@ 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,
|
||||
hostname: '127.0.0.1',
|
||||
port: hasStartArg ? 3002 : 3001,
|
||||
};
|
||||
|
||||
function startServer(options = {}, cb = Function.prototype) {
|
||||
|
@ -14,7 +13,7 @@ function startServer(options = {}, cb = Function.prototype) {
|
|||
middleware: [
|
||||
{
|
||||
route: '/_blank.html',
|
||||
handle: function(req, res, next) {
|
||||
handle: function (req, res, next) {
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.end('');
|
||||
next();
|
||||
|
@ -26,7 +25,8 @@ function startServer(options = {}, cb = Function.prototype) {
|
|||
rewriteRules: [
|
||||
// Replace docsify-related CDN URLs with local paths
|
||||
{
|
||||
match: /(https?:)?\/\/cdn\.jsdelivr\.net\/npm\/docsify(@\d?\.?\d?\.?\d)?\/lib\//g,
|
||||
match:
|
||||
/(https?:)?\/\/cdn\.jsdelivr\.net\/npm\/docsify(@\d?\.?\d?\.?\d)?\/lib\//g,
|
||||
replace: '/lib/',
|
||||
},
|
||||
],
|
||||
|
@ -42,7 +42,7 @@ function startServer(options = {}, cb = Function.prototype) {
|
|||
snippetOptions: {
|
||||
rule: {
|
||||
match: /<\/body>/i,
|
||||
fn: function(snippet, match) {
|
||||
fn: function (snippet, match) {
|
||||
// Override changelog alias to load local changelog (see routes)
|
||||
const injectJS = `
|
||||
<script>
|
||||
|
@ -64,6 +64,10 @@ function startServer(options = {}, cb = Function.prototype) {
|
|||
|
||||
console.log('\n');
|
||||
|
||||
// Set TEST_HOST environment variable
|
||||
process.env.TEST_HOST = `http://${serverConfig.hostname}:${serverConfig.port}`;
|
||||
|
||||
// Start server
|
||||
browserSync.init(
|
||||
// Config
|
||||
{
|
||||
|
@ -93,7 +97,7 @@ function stopServer() {
|
|||
if (hasStartArg) {
|
||||
startServer({
|
||||
open: true,
|
||||
port: serverConfig.port + 1,
|
||||
port: serverConfig.port,
|
||||
directory: true,
|
||||
startPath: '/docs',
|
||||
});
|
||||
|
@ -107,5 +111,5 @@ module.exports = {
|
|||
start: startServer,
|
||||
startAsync: startServerAsync,
|
||||
stop: stopServer,
|
||||
TEST_HOST: `http://${serverConfig.host}:${serverConfig.port}`,
|
||||
TEST_HOST: `http://${serverConfig.hostname}:${serverConfig.port}`,
|
||||
};
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = {
|
||||
extends: ['plugin:jest-playwright/recommended'],
|
||||
extends: ['plugin:playwright/playwright-test'],
|
||||
};
|
||||
|
|
Before Width: | Height: | Size: 172 KiB |
Before Width: | Height: | Size: 147 KiB |
Before Width: | Height: | Size: 168 KiB |
Before Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 174 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.9 KiB |
|
@ -1,48 +1,37 @@
|
|||
// Modules, constants, and variables
|
||||
// -----------------------------------------------------------------------------
|
||||
const docsifyInit = require('../helpers/docsify-init');
|
||||
const { test, expect } = require('./fixtures/docsify-init-fixture');
|
||||
|
||||
// Suite
|
||||
// -----------------------------------------------------------------------------
|
||||
describe(`Example Tests`, function() {
|
||||
test.describe('Example Tests', () => {
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
test('dom manipulation', async () => {
|
||||
test('dom manipulation', async ({ page }) => {
|
||||
const testText = 'This is a test';
|
||||
const testHTML = `<h1>Test</h1><p>${testText}</p>`;
|
||||
|
||||
// Inject HTML
|
||||
// https://playwright.dev/#path=docs%2Fapi.md&q=pagesetcontenthtml-options
|
||||
await page.setContent(testHTML);
|
||||
|
||||
// Add class to <body> 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');
|
||||
// Get reference to page element
|
||||
const bodyElm = page.locator('body');
|
||||
const pElm = page.locator('body > p');
|
||||
|
||||
// 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 });
|
||||
// Add class to element and test
|
||||
await bodyElm.evaluate(elm => elm.classList.add('foo'));
|
||||
|
||||
// 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();
|
||||
// Tests
|
||||
await expect(bodyElm).toHaveClass('foo');
|
||||
await expect(bodyElm).toContainText('Test');
|
||||
await expect(pElm).toHaveCount(1);
|
||||
await expect(pElm).toHaveText(testText);
|
||||
await expect(pElm).not.toHaveText('NOPE');
|
||||
});
|
||||
|
||||
test('javascript in browser context', async () => {
|
||||
test('javascript in browser context', async ({ page }) => {
|
||||
// Get native DOM values
|
||||
// https://playwright.dev/#path=docs%2Fapi.md&q=pageevaluatepagefunction-arg
|
||||
const clientDimensions = await page.evaluate(() => {
|
||||
return {
|
||||
width: document.documentElement.clientWidth,
|
||||
|
@ -56,7 +45,6 @@ describe(`Example Tests`, function() {
|
|||
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(
|
||||
|
@ -71,7 +59,6 @@ describe(`Example Tests`, function() {
|
|||
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
|
||||
|
@ -79,7 +66,7 @@ describe(`Example Tests`, function() {
|
|||
}
|
||||
|
||||
const functionResult = await page.evaluate(`
|
||||
${add.toString()}
|
||||
const add = ${add.toString()};
|
||||
|
||||
const result = add(1, 2, 3);
|
||||
|
||||
|
@ -89,13 +76,11 @@ describe(`Example Tests`, function() {
|
|||
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(`${TEST_HOST}/_blank.html`);
|
||||
test('manual docsify site using playwright methods', async ({ page }) => {
|
||||
// Add docsify target element
|
||||
await page.setContent('<div id="app"></div>');
|
||||
|
||||
// Set docsify configuration
|
||||
// https://playwright.dev/#path=docs%2Fapi.md&q=pageevaluatepagefunction-arg
|
||||
await page.evaluate(() => {
|
||||
window.$docsify = {
|
||||
el: '#app',
|
||||
|
@ -104,58 +89,42 @@ describe(`Example Tests`, function() {
|
|||
};
|
||||
});
|
||||
|
||||
// Add docsify target element
|
||||
// https://playwright.dev/#path=docs%2Fapi.md&q=pageevalselector-pagefunction-arg
|
||||
await page.$eval('body', elm => {
|
||||
elm.innerHTML = '<div id="app"></div>';
|
||||
});
|
||||
|
||||
// Inject docsify theme (vue.css)
|
||||
// https://playwright.dev/#path=docs%2Fapi.md&q=pageaddstyletagoptions
|
||||
await page.addStyleTag({ url: '/lib/themes/vue.css' });
|
||||
|
||||
// Inject docsify.js
|
||||
// https://playwright.dev/#path=docs%2Fapi.md&q=pageaddscripttagoptions
|
||||
await page.addScriptTag({ url: '/lib/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);
|
||||
// const $docsify = await page.evaluateHandle(() => window.$docsify);
|
||||
|
||||
// Test object property and value
|
||||
expect($docsify).toHaveProperty('themeColor', 'red');
|
||||
});
|
||||
|
||||
test('Docsify /docs/ site using docsifyInit()', async () => {
|
||||
test('Docsify /docs/ site using docsifyInit()', async ({ page }) => {
|
||||
// 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',
|
||||
const mainElm = page.locator('#main');
|
||||
await expect(mainElm).toHaveCount(1);
|
||||
await expect(mainElm).toContainText(
|
||||
'A magical documentation site generator'
|
||||
);
|
||||
});
|
||||
|
||||
test('custom docsify site using docsifyInit()', async () => {
|
||||
test('custom docsify site using docsifyInit()', async ({ page }) => {
|
||||
const docsifyInitConfig = {
|
||||
config: {
|
||||
name: 'Docsify Name',
|
||||
|
@ -210,7 +179,6 @@ describe(`Example Tests`, function() {
|
|||
|
||||
await docsifyInit({
|
||||
...docsifyInitConfig,
|
||||
// _debug: true,
|
||||
// _logHTML: true,
|
||||
});
|
||||
|
||||
|
@ -219,24 +187,22 @@ describe(`Example Tests`, function() {
|
|||
// Verify config options
|
||||
expect(typeof $docsify).toEqual('object');
|
||||
expect($docsify).toHaveProperty('themeColor', 'red');
|
||||
await expect(page).toHaveText('.app-name', 'Docsify Name');
|
||||
await expect(page.locator('.app-name')).toHaveText('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
|
||||
await expect(page.locator('section.cover h1')).toHaveText('Docsify Test'); // Coverpage
|
||||
await expect(page.locator('nav.app-nav')).toHaveText('docsify.js.org'); // Navbar
|
||||
await expect(page.locator('aside.sidebar')).toContainText('Test Page'); // Sidebar
|
||||
await expect(page.locator('#main')).toContainText('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',
|
||||
});
|
||||
await expect(page.locator(`script[src$="${scriptURL}"]`)).toHaveCount(1);
|
||||
}
|
||||
|
||||
// Verify docsifyInitConfig.scriptURLs were executed
|
||||
await expect(page).toHaveSelector('body[data-test-scripturls]');
|
||||
await expect(page).toHaveSelector('.search input[type="search"]');
|
||||
await expect(page.locator('body[data-test-scripturls]')).toHaveCount(1);
|
||||
await expect(page.locator('.search input[type="search"]')).toHaveCount(1);
|
||||
|
||||
// Verify docsifyInitConfig.script was added to the DOM
|
||||
expect(
|
||||
|
@ -248,16 +214,13 @@ describe(`Example Tests`, function() {
|
|||
).toBe(true);
|
||||
|
||||
// Verify docsifyInitConfig.script was executed
|
||||
await expect(page).toHaveSelector('body[data-test-script]');
|
||||
await expect(page.locator('body[data-test-script]')).toHaveCount(1);
|
||||
|
||||
// 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',
|
||||
}
|
||||
);
|
||||
await expect(
|
||||
page.locator(`link[rel*="stylesheet"][href$="${styleURL}"]`)
|
||||
).toHaveCount(1);
|
||||
}
|
||||
|
||||
// Verify docsifyInitConfig.style was added to the DOM
|
||||
|
@ -272,73 +235,68 @@ describe(`Example Tests`, function() {
|
|||
// 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');
|
||||
await expect(page.locator('#main')).toContainText('This is a custom route');
|
||||
});
|
||||
|
||||
test('image snapshots', async () => {
|
||||
await docsifyInit({
|
||||
config: {
|
||||
name: 'Docsify Test',
|
||||
},
|
||||
markdown: {
|
||||
homepage: `
|
||||
# The Cosmos Awaits
|
||||
// test.fixme('image snapshots', async ({ page }) => {
|
||||
// await docsifyInit({
|
||||
// config: {
|
||||
// name: 'Docsify Test',
|
||||
// },
|
||||
// markdown: {
|
||||
// homepage: `
|
||||
// # The Cosmos Awaits
|
||||
|
||||
[Carl Sagan](https://en.wikipedia.org/wiki/Carl_Sagan)
|
||||
// [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.
|
||||
// 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.
|
||||
// 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.
|
||||
// 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,
|
||||
});
|
||||
// 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`],
|
||||
// // _logHTML: true,
|
||||
// });
|
||||
|
||||
// Viewport screenshot
|
||||
const screenshot1 = await page.screenshot();
|
||||
expect(screenshot1).toMatchImageSnapshot();
|
||||
// // Viewport screenshot
|
||||
// const viewportShot = await page.screenshot();
|
||||
// expect(viewportShot).toMatchSnapshot('viewport.png');
|
||||
|
||||
// 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();
|
||||
});
|
||||
// // Element screenshot
|
||||
// const elmHandle = await page.locator('h1').first();
|
||||
// const elmShot = await elmHandle.screenshot();
|
||||
// expect(elmShot).toMatchSnapshot('element.png');
|
||||
// });
|
||||
});
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
const base = require('@playwright/test');
|
||||
|
||||
exports.test = base.test.extend({
|
||||
page: async ({ page }, use) => {
|
||||
global.page = page;
|
||||
|
||||
// Navigate to a real URL by default
|
||||
// Playwright tests are executed on "about:blank" by default, which will
|
||||
// cause operations that require the window location to be a valid URL to
|
||||
// fail (e.g. AJAX requests). Navigating to a blank document with a real
|
||||
// URL solved this problem.
|
||||
await page.goto('/_blank.html');
|
||||
await use(page);
|
||||
},
|
||||
});
|
||||
exports.expect = base.expect;
|
|
@ -1,28 +1,28 @@
|
|||
const docsifyInit = require('../helpers/docsify-init');
|
||||
const { test, expect } = require('./fixtures/docsify-init-fixture');
|
||||
|
||||
describe(`Index file hosting`, function() {
|
||||
test.describe('Index file hosting', () => {
|
||||
const sharedOptions = {
|
||||
config: {
|
||||
basePath: `${TEST_HOST}/docs/index.html#/`,
|
||||
basePath: '/docs/index.html#/',
|
||||
},
|
||||
testURL: `${TEST_HOST}/docs/index.html#/`,
|
||||
testURL: '/docs/index.html#/',
|
||||
};
|
||||
|
||||
test('should serve from index file', async () => {
|
||||
test('should serve from index file', async ({ page }) => {
|
||||
await docsifyInit(sharedOptions);
|
||||
|
||||
await expect(page).toHaveText(
|
||||
'#main',
|
||||
await expect(page.locator('#main')).toContainText(
|
||||
'A magical documentation site generator'
|
||||
);
|
||||
expect(page.url()).toMatch(/index\.html#\/$/);
|
||||
});
|
||||
|
||||
test('should use index file links in sidebar from index file hosting', async () => {
|
||||
test('should use index file links in sidebar from index file hosting', async ({
|
||||
page,
|
||||
}) => {
|
||||
await docsifyInit(sharedOptions);
|
||||
|
||||
await page.click('a[href="#/quickstart"]');
|
||||
await expect(page).toHaveText('#main', 'Quick start');
|
||||
await expect(page.locator('#main')).toContainText('Quick start');
|
||||
expect(page.url()).toMatch(/index\.html#\/quickstart$/);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
const docsifyInit = require('../helpers/docsify-init');
|
||||
const { test, expect } = require('./fixtures/docsify-init-fixture');
|
||||
|
||||
// Suite
|
||||
// -----------------------------------------------------------------------------
|
||||
describe('Search Plugin Tests', function() {
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
test('search readme', async () => {
|
||||
test.describe('Search Plugin Tests', () => {
|
||||
test('search readme', async ({ page }) => {
|
||||
const docsifyInitConfig = {
|
||||
markdown: {
|
||||
homepage: `
|
||||
|
@ -27,15 +24,19 @@ describe('Search Plugin Tests', function() {
|
|||
scriptURLs: ['/lib/plugins/search.min.js'],
|
||||
};
|
||||
|
||||
const searchFieldElm = page.locator('input[type=search]');
|
||||
const resultsHeadingElm = page.locator('.results-panel h2');
|
||||
|
||||
await docsifyInit(docsifyInitConfig);
|
||||
await page.fill('input[type=search]', 'hello');
|
||||
await expect(page).toEqualText('.results-panel h2', 'Hello World');
|
||||
|
||||
await searchFieldElm.fill('hello');
|
||||
await expect(resultsHeadingElm).toHaveText('Hello World');
|
||||
await page.click('.clear-button');
|
||||
await page.fill('input[type=search]', 'test');
|
||||
await expect(page).toEqualText('.results-panel h2', 'Test Page');
|
||||
await searchFieldElm.fill('test');
|
||||
await expect(resultsHeadingElm).toHaveText('Test Page');
|
||||
});
|
||||
|
||||
test('search ignore title', async () => {
|
||||
test('search ignore title', async ({ page }) => {
|
||||
const docsifyInitConfig = {
|
||||
markdown: {
|
||||
homepage: `
|
||||
|
@ -65,15 +66,20 @@ describe('Search Plugin Tests', function() {
|
|||
},
|
||||
scriptURLs: ['/lib/plugins/search.min.js'],
|
||||
};
|
||||
|
||||
const searchFieldElm = page.locator('input[type=search]');
|
||||
const resultsHeadingElm = page.locator('.results-panel h2');
|
||||
|
||||
await docsifyInit(docsifyInitConfig);
|
||||
await page.fill('input[type=search]', 'repository1');
|
||||
await expect(page).toEqualText('.results-panel h2', 'GitHub Pages ignore1');
|
||||
|
||||
await searchFieldElm.fill('repository1');
|
||||
await expect(resultsHeadingElm).toHaveText('GitHub Pages ignore1');
|
||||
await page.click('.clear-button');
|
||||
await page.fill('input[type=search]', 'repository2');
|
||||
await expect(page).toEqualText('.results-panel h2', 'GitHub Pages ignore2');
|
||||
await searchFieldElm.fill('repository2');
|
||||
await expect(resultsHeadingElm).toHaveText('GitHub Pages ignore2');
|
||||
});
|
||||
|
||||
test('search only one homepage', async () => {
|
||||
test('search only one homepage', async ({ page }) => {
|
||||
const docsifyInitConfig = {
|
||||
markdown: {
|
||||
sidebar: `
|
||||
|
@ -96,17 +102,21 @@ describe('Search Plugin Tests', function() {
|
|||
scriptURLs: ['/lib/plugins/search.js'],
|
||||
};
|
||||
|
||||
const searchFieldElm = page.locator('input[type=search]');
|
||||
const resultsHeadingElm = page.locator('.results-panel h2');
|
||||
const resultElm = page.locator('.matching-post');
|
||||
|
||||
await docsifyInit(docsifyInitConfig);
|
||||
await page.fill('input[type=search]', 'hello');
|
||||
await expect(page).toHaveSelector('.matching-post');
|
||||
expect(await page.$$eval('.matching-post', elms => elms.length)).toBe(1);
|
||||
await expect(page).toEqualText('.results-panel h2', 'Hello World');
|
||||
|
||||
await searchFieldElm.fill('hello');
|
||||
await expect(resultElm).toHaveCount(1);
|
||||
await expect(resultsHeadingElm).toHaveText('Hello World');
|
||||
await page.click('.clear-button');
|
||||
await page.fill('input[type=search]', 'test');
|
||||
await expect(page).toEqualText('.results-panel h2', 'Test Page');
|
||||
await searchFieldElm.fill('test');
|
||||
await expect(resultsHeadingElm).toHaveText('Test Page');
|
||||
});
|
||||
|
||||
test('search ignore diacritical marks', async () => {
|
||||
test('search ignore diacritical marks', async ({ page }) => {
|
||||
const docsifyInitConfig = {
|
||||
markdown: {
|
||||
homepage: `
|
||||
|
@ -117,15 +127,20 @@ describe('Search Plugin Tests', function() {
|
|||
},
|
||||
scriptURLs: ['/lib/plugins/search.min.js'],
|
||||
};
|
||||
|
||||
const searchFieldElm = page.locator('input[type=search]');
|
||||
const resultsHeadingElm = page.locator('.results-panel h2');
|
||||
|
||||
await docsifyInit(docsifyInitConfig);
|
||||
await page.fill('input[type=search]', 'documentacion');
|
||||
await expect(page).toEqualText('.results-panel h2', 'Que es');
|
||||
|
||||
await searchFieldElm.fill('documentacion');
|
||||
await expect(resultsHeadingElm).toHaveText('Que es');
|
||||
await page.click('.clear-button');
|
||||
await page.fill('input[type=search]', 'estáticos');
|
||||
await expect(page).toEqualText('.results-panel h2', 'Que es');
|
||||
await searchFieldElm.fill('estáticos');
|
||||
await expect(resultsHeadingElm).toHaveText('Que es');
|
||||
});
|
||||
|
||||
test('search when there is no title', async () => {
|
||||
test('search when there is no title', async ({ page }) => {
|
||||
const docsifyInitConfig = {
|
||||
markdown: {
|
||||
homepage: `
|
||||
|
@ -146,14 +161,19 @@ describe('Search Plugin Tests', function() {
|
|||
},
|
||||
scriptURLs: ['/lib/plugins/search.min.js'],
|
||||
};
|
||||
|
||||
const searchFieldElm = page.locator('input[type=search]');
|
||||
const resultsHeadingElm = page.locator('.results-panel h2');
|
||||
|
||||
await docsifyInit(docsifyInitConfig);
|
||||
await page.fill('input[type=search]', 'paragraph');
|
||||
await expect(page).toEqualText('.results-panel h2', 'Home Page');
|
||||
|
||||
await searchFieldElm.fill('paragraph');
|
||||
await expect(resultsHeadingElm).toHaveText('Home Page');
|
||||
await page.click('.clear-button');
|
||||
await page.fill('input[type=search]', 'Support');
|
||||
await expect(page).toEqualText('.results-panel h2', 'changelog');
|
||||
await searchFieldElm.fill('Support');
|
||||
await expect(resultsHeadingElm).toHaveText('changelog');
|
||||
await page.click('.clear-button');
|
||||
await page.fill('input[type=search]', 'hello');
|
||||
await expect(page).toEqualText('.results-panel h2', 'Changelog Title');
|
||||
await searchFieldElm.fill('hello');
|
||||
await expect(resultsHeadingElm).toHaveText('Changelog Title');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const docsifyInit = require('../helpers/docsify-init');
|
||||
const { test, expect } = require('./fixtures/docsify-init-fixture');
|
||||
|
||||
describe(`Security`, function() {
|
||||
test.describe('Security - Cross Site Scripting (XSS)', () => {
|
||||
const sharedOptions = {
|
||||
markdown: {
|
||||
homepage: '# Hello World',
|
||||
|
@ -9,24 +10,25 @@ describe(`Security`, function() {
|
|||
'test.md': '# Test Page',
|
||||
},
|
||||
};
|
||||
const slashStrings = ['//', '///'];
|
||||
|
||||
describe(`Cross Site Scripting (XSS)`, function() {
|
||||
const slashStrings = ['//', '///'];
|
||||
for (let slashString of slashStrings) {
|
||||
const hash = `#${slashString}domain.com/file.md`;
|
||||
|
||||
for (const slashString of slashStrings) {
|
||||
const hash = `#${slashString}domain.com/file.md`;
|
||||
test(`should not load remote content from hash (${hash})`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const mainElm = page.locator('#main');
|
||||
|
||||
test(`should not load remote content from hash (${hash})`, async () => {
|
||||
await docsifyInit(sharedOptions);
|
||||
await expect(page).toHaveText('#main', 'Hello World');
|
||||
await page.evaluate(() => (location.hash = '#/test'));
|
||||
await expect(page).toHaveText('#main', 'Test Page');
|
||||
await page.evaluate(newHash => {
|
||||
location.hash = newHash;
|
||||
}, hash);
|
||||
await expect(page).toHaveText('#main', 'Hello World');
|
||||
expect(page.url()).toMatch(/#\/$/);
|
||||
});
|
||||
}
|
||||
});
|
||||
await docsifyInit(sharedOptions);
|
||||
await expect(mainElm).toContainText('Hello World');
|
||||
await page.evaluate(() => (location.hash = '#/test'));
|
||||
await expect(mainElm).toContainText('Test Page');
|
||||
await page.evaluate(newHash => {
|
||||
location.hash = newHash;
|
||||
}, hash);
|
||||
await expect(mainElm).toContainText('Hello World');
|
||||
expect(page.url()).toMatch(/#\/$/);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
const docsifyInit = require('../helpers/docsify-init');
|
||||
const { test, expect } = require('./fixtures/docsify-init-fixture');
|
||||
|
||||
// Suite
|
||||
// -----------------------------------------------------------------------------
|
||||
describe('Sidebar Tests', function() {
|
||||
test.describe('Sidebar Tests', () => {
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
test('Active Test', async () => {
|
||||
test('Active Test', async ({ page }) => {
|
||||
const docsifyInitConfig = {
|
||||
markdown: {
|
||||
sidebar: `
|
||||
|
@ -39,32 +40,32 @@ describe('Sidebar Tests', function() {
|
|||
},
|
||||
};
|
||||
|
||||
const activeLinkElm = page.locator('.sidebar-nav li[class=active]');
|
||||
|
||||
await docsifyInit(docsifyInitConfig);
|
||||
|
||||
await page.click('a[href="#/test%20space"]');
|
||||
await expect(page).toEqualText(
|
||||
'.sidebar-nav li[class=active]',
|
||||
'Test Space'
|
||||
);
|
||||
await expect(activeLinkElm).toHaveText('Test Space');
|
||||
expect(page.url()).toMatch(/\/test%20space$/);
|
||||
|
||||
await page.click('a[href="#/test_foo"]');
|
||||
await expect(page).toEqualText('.sidebar-nav li[class=active]', 'Test _');
|
||||
await expect(activeLinkElm).toHaveText('Test _');
|
||||
expect(page.url()).toMatch(/\/test_foo$/);
|
||||
|
||||
await page.click('a[href="#/test-foo"]');
|
||||
await expect(page).toEqualText('.sidebar-nav li[class=active]', 'Test -');
|
||||
await expect(activeLinkElm).toHaveText('Test -');
|
||||
expect(page.url()).toMatch(/\/test-foo$/);
|
||||
|
||||
await page.click('a[href="#/test.foo"]');
|
||||
expect(page.url()).toMatch(/\/test.foo$/);
|
||||
await expect(page).toEqualText('.sidebar-nav li[class=active]', 'Test .');
|
||||
await expect(activeLinkElm).toHaveText('Test .');
|
||||
|
||||
await page.click('a[href="#/test>foo"]');
|
||||
await expect(page).toEqualText('.sidebar-nav li[class=active]', 'Test >');
|
||||
await expect(activeLinkElm).toHaveText('Test >');
|
||||
expect(page.url()).toMatch(/\/test%3Efoo$/);
|
||||
|
||||
await page.click('a[href="#/test"]');
|
||||
await expect(page).toEqualText('.sidebar-nav li[class=active]', 'Test');
|
||||
await expect(activeLinkElm).toHaveText('Test');
|
||||
expect(page.url()).toMatch(/\/test$/);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
const stripIndent = require('common-tags/lib/stripIndent');
|
||||
const docsifyInit = require('../helpers/docsify-init');
|
||||
const { test, expect } = require('./fixtures/docsify-init-fixture');
|
||||
|
||||
const vueURLs = [
|
||||
'/node_modules/vue2/dist/vue.js',
|
||||
'/node_modules/vue3/dist/vue.global.js',
|
||||
];
|
||||
|
||||
describe('Vue.js Compatibility', function() {
|
||||
test.describe('Vue.js Compatibility', () => {
|
||||
function getSharedConfig() {
|
||||
const config = {
|
||||
config: {
|
||||
|
@ -15,7 +16,7 @@ describe('Vue.js Compatibility', function() {
|
|||
template: `
|
||||
<button @click="counter++">{{ counter }}</button>
|
||||
`,
|
||||
data: function() {
|
||||
data: function () {
|
||||
return {
|
||||
counter: 0,
|
||||
};
|
||||
|
@ -23,7 +24,7 @@ describe('Vue.js Compatibility', function() {
|
|||
},
|
||||
},
|
||||
vueGlobalOptions: {
|
||||
data: function() {
|
||||
data: function () {
|
||||
return {
|
||||
counter: 0,
|
||||
msg: 'vueglobaloptions',
|
||||
|
@ -32,7 +33,7 @@ describe('Vue.js Compatibility', function() {
|
|||
},
|
||||
vueMounts: {
|
||||
'#vuemounts': {
|
||||
data: function() {
|
||||
data: function () {
|
||||
return {
|
||||
counter: 0,
|
||||
msg: 'vuemounts',
|
||||
|
@ -96,9 +97,11 @@ describe('Vue.js Compatibility', function() {
|
|||
for (const vueURL of vueURLs) {
|
||||
const vueVersion = Number(vueURL.match(/vue(\d+)/)[1]); // 2|3
|
||||
|
||||
describe(`Vue v${vueVersion}`, function() {
|
||||
test.describe(`Vue v${vueVersion}`, () => {
|
||||
for (const executeScript of [true, undefined]) {
|
||||
test(`renders content when executeScript is ${executeScript}`, async () => {
|
||||
test(`renders content when executeScript is ${executeScript}`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const docsifyInitConfig = getSharedConfig();
|
||||
|
||||
docsifyInitConfig.config.executeScript = executeScript;
|
||||
|
@ -107,45 +110,48 @@ describe('Vue.js Compatibility', function() {
|
|||
await docsifyInit(docsifyInitConfig);
|
||||
|
||||
// Static
|
||||
await expect(page).toEqualText('#vuefor', '12345');
|
||||
await expect(page).toEqualText('#vuecomponent', '0');
|
||||
await expect(page).toEqualText(
|
||||
'#vueglobaloptions p',
|
||||
await expect(page.locator('#vuefor')).toHaveText('12345');
|
||||
await expect(page.locator('#vuecomponent')).toHaveText('0');
|
||||
await expect(page.locator('#vueglobaloptions p')).toHaveText(
|
||||
'vueglobaloptions'
|
||||
);
|
||||
await expect(page).toEqualText('#vueglobaloptions span', '0');
|
||||
await expect(page).toEqualText('#vuemounts p', 'vuemounts');
|
||||
await expect(page).toEqualText('#vuemounts span', '0');
|
||||
await expect(page).toEqualText('#vuescript p', 'vuescript');
|
||||
await expect(page).toEqualText('#vuescript span', '0');
|
||||
await expect(page.locator('#vueglobaloptions > span')).toHaveText(
|
||||
'0'
|
||||
);
|
||||
await expect(page.locator('#vuemounts p')).toHaveText('vuemounts');
|
||||
await expect(page.locator('#vuemounts > span')).toHaveText('0');
|
||||
await expect(page.locator('#vuescript p')).toHaveText('vuescript');
|
||||
await expect(page.locator('#vuescript > span')).toHaveText('0');
|
||||
|
||||
// Reactive
|
||||
await page.click('#vuecomponent');
|
||||
await expect(page).toEqualText('#vuecomponent', '1');
|
||||
await expect(page.locator('#vuecomponent')).toHaveText('1');
|
||||
await page.click('#vueglobaloptions button');
|
||||
await expect(page).toEqualText('#vueglobaloptions span', '1');
|
||||
await expect(page.locator('#vueglobaloptions > span')).toHaveText(
|
||||
'1'
|
||||
);
|
||||
await page.click('#vuemounts button');
|
||||
await expect(page).toEqualText('#vuemounts span', '1');
|
||||
await expect(page.locator('#vuemounts > span')).toHaveText('1');
|
||||
await page.click('#vuescript button');
|
||||
await expect(page).toEqualText('#vuescript span', '1');
|
||||
await expect(page.locator('#vuescript > span')).toHaveText('1');
|
||||
});
|
||||
}
|
||||
|
||||
test(`ignores content when Vue is not present`, async () => {
|
||||
test(`ignores content when Vue is not present`, async ({ page }) => {
|
||||
const docsifyInitConfig = getSharedConfig();
|
||||
|
||||
await docsifyInit(docsifyInitConfig);
|
||||
await page.evaluate(() => {
|
||||
return 'Vue' in window === false;
|
||||
});
|
||||
await expect(page).toEqualText('#vuefor', '{{ i }}');
|
||||
await expect(page).toEqualText('#vuecomponent', '---');
|
||||
await expect(page).toEqualText('#vueglobaloptions p', '---');
|
||||
await expect(page).toEqualText('#vuemounts p', '---');
|
||||
await expect(page).toEqualText('#vuescript p', '---');
|
||||
await page.evaluate(() => 'Vue' in window === false);
|
||||
await expect(page.locator('#vuefor')).toHaveText('{{ i }}');
|
||||
await expect(page.locator('#vuecomponent')).toHaveText('---');
|
||||
await expect(page.locator('#vueglobaloptions p')).toHaveText('---');
|
||||
await expect(page.locator('#vuemounts p')).toHaveText('---');
|
||||
await expect(page.locator('#vuescript p')).toHaveText('---');
|
||||
});
|
||||
|
||||
test(`ignores content when vueComponents, vueMounts, and vueGlobalOptions are undefined`, async () => {
|
||||
test(`ignores content when vueComponents, vueMounts, and vueGlobalOptions are undefined`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const docsifyInitConfig = getSharedConfig();
|
||||
|
||||
docsifyInitConfig.config.vueComponents = undefined;
|
||||
|
@ -154,52 +160,58 @@ describe('Vue.js Compatibility', function() {
|
|||
docsifyInitConfig.scriptURLs = vueURL;
|
||||
|
||||
await docsifyInit(docsifyInitConfig);
|
||||
await expect(page).toEqualText('#vuefor', '{{ i }}');
|
||||
await expect(page).toEqualText('#vuecomponent', '---');
|
||||
await expect(page).toEqualText('#vueglobaloptions p', '---');
|
||||
await expect(page).toEqualText('#vuemounts p', '---');
|
||||
await expect(page).toEqualText('#vuescript p', 'vuescript');
|
||||
await expect(page.locator('#vuefor')).toHaveText('{{ i }}');
|
||||
await expect(page.locator('#vuecomponent')).toHaveText('---');
|
||||
await expect(page.locator('#vueglobaloptions p')).toHaveText('---');
|
||||
await expect(page.locator('#vuemounts p')).toHaveText('---');
|
||||
await expect(page.locator('#vuescript p')).toHaveText('vuescript');
|
||||
});
|
||||
|
||||
test(`ignores content when vueGlobalOptions is undefined`, async () => {
|
||||
test(`ignores content when vueGlobalOptions is undefined`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const docsifyInitConfig = getSharedConfig();
|
||||
|
||||
docsifyInitConfig.config.vueGlobalOptions = undefined;
|
||||
docsifyInitConfig.scriptURLs = vueURL;
|
||||
|
||||
await docsifyInit(docsifyInitConfig);
|
||||
await expect(page).toEqualText('#vuefor', '12345');
|
||||
await expect(page).toEqualText('#vuecomponent', '0');
|
||||
expect(await page.innerText('#vueglobaloptions p')).toBe('');
|
||||
await expect(page).toEqualText('#vuemounts p', 'vuemounts');
|
||||
await expect(page).toEqualText('#vuescript p', 'vuescript');
|
||||
await expect(page.locator('#vuefor')).toHaveText('12345');
|
||||
await expect(page.locator('#vuecomponent')).toHaveText('0');
|
||||
await expect(page.locator('#vuecomponent')).toHaveText('0');
|
||||
expect(await page.locator('#vueglobaloptions p').innerText()).toBe('');
|
||||
await expect(page.locator('#vuemounts p')).toHaveText('vuemounts');
|
||||
await expect(page.locator('#vuescript p')).toHaveText('vuescript');
|
||||
});
|
||||
|
||||
test(`ignores content when vueMounts is undefined`, async () => {
|
||||
test(`ignores content when vueMounts is undefined`, async ({ page }) => {
|
||||
const docsifyInitConfig = getSharedConfig();
|
||||
|
||||
docsifyInitConfig.config.vueMounts['#vuemounts'] = undefined;
|
||||
docsifyInitConfig.scriptURLs = vueURL;
|
||||
|
||||
await docsifyInit(docsifyInitConfig);
|
||||
await expect(page).toEqualText('#vuefor', '12345');
|
||||
await expect(page).toEqualText('#vuecomponent', '0');
|
||||
await expect(page).toEqualText(
|
||||
'#vueglobaloptions p',
|
||||
await expect(page.locator('#vuefor')).toHaveText('12345');
|
||||
await expect(page.locator('#vuecomponent')).toHaveText('0');
|
||||
await expect(page.locator('#vueglobaloptions p')).toHaveText(
|
||||
'vueglobaloptions'
|
||||
);
|
||||
await expect(page).toEqualText('#vuemounts p', 'vueglobaloptions');
|
||||
await expect(page).toEqualText('#vuescript p', 'vuescript');
|
||||
await expect(page.locator('#vuemounts p')).toHaveText(
|
||||
'vueglobaloptions'
|
||||
);
|
||||
await expect(page.locator('#vuescript p')).toHaveText('vuescript');
|
||||
});
|
||||
|
||||
test(`ignores <script> when executeScript is false`, async () => {
|
||||
test(`ignores <script> when executeScript is false`, async ({ page }) => {
|
||||
const docsifyInitConfig = getSharedConfig();
|
||||
|
||||
docsifyInitConfig.config.executeScript = false;
|
||||
docsifyInitConfig.scriptURLs = vueURL;
|
||||
|
||||
await docsifyInit(docsifyInitConfig);
|
||||
await expect(page).toEqualText('#vuescript p', 'vueglobaloptions');
|
||||
await expect(page.locator('#vuescript p')).toHaveText(
|
||||
'vueglobaloptions'
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
/* global jestPlaywright page */
|
||||
import mock, { proxy } from 'xhr-mock';
|
||||
import { waitForSelector } from './wait-for';
|
||||
/* globals page */
|
||||
|
||||
const axios = require('axios');
|
||||
const mock = require('xhr-mock').default;
|
||||
const prettier = require('prettier');
|
||||
const stripIndent = require('common-tags/lib/stripIndent');
|
||||
const { proxy } = require('xhr-mock');
|
||||
const { waitForSelector } = require('./wait-for');
|
||||
|
||||
const docsifyPATH = '../../lib/docsify.js'; // JSDOM
|
||||
const docsifyURL = '/lib/docsify.js'; // Playwright
|
||||
const isJSDOM = 'window' in global;
|
||||
const isPlaywright = 'page' in global;
|
||||
|
||||
/**
|
||||
* Jest / Playwright helper for creating custom docsify test sites
|
||||
|
@ -28,17 +27,19 @@ const isPlaywright = 'page' in global;
|
|||
* @param {String} [options.style] CSS to inject via <style> tag
|
||||
* @param {String|String[]} [options.styleURLs=['/lib/themes/vue.css']] External CSS to inject via <link rel="stylesheet"> tag(s)
|
||||
* @param {String} [options.testURL] URL to set as window.location.href
|
||||
* @param {String} [options.waitForSelector='#main'] Element to wait for before returning promsie
|
||||
* @param {String} [options._debug] initiate debugger after site is created
|
||||
* @param {String} [options.waitForSelector='#main'] Element to wait for before returning promise
|
||||
* @param {Boolean|Object|String} [options._logHTML] Logs HTML to console after initialization. Accepts CSS selector.
|
||||
* @param {Boolean} [options._logHTML.format=true] Formats HTML output
|
||||
* @param {String} [options._logHTML.selector='html'] CSS selector(s) to match and log HTML for
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function docsifyInit(options = {}) {
|
||||
const isJSDOM = 'window' in global;
|
||||
const isPlaywright = 'page' in global;
|
||||
|
||||
const defaults = {
|
||||
config: {
|
||||
basePath: TEST_HOST,
|
||||
basePath: process.env.TEST_HOST,
|
||||
el: '#app',
|
||||
},
|
||||
html: `
|
||||
|
@ -63,7 +64,7 @@ async function docsifyInit(options = {}) {
|
|||
scriptURLs: [],
|
||||
style: '',
|
||||
styleURLs: [],
|
||||
testURL: `${TEST_HOST}/docsify-init.html`,
|
||||
testURL: `${process.env.TEST_HOST}/docsify-init.html`,
|
||||
waitForSelector: '#main > *',
|
||||
};
|
||||
const settings = {
|
||||
|
@ -80,13 +81,16 @@ async function docsifyInit(options = {}) {
|
|||
|
||||
const updateBasePath = config => {
|
||||
if (config.basePath) {
|
||||
config.basePath = new URL(config.basePath, TEST_HOST).href;
|
||||
config.basePath = new URL(
|
||||
config.basePath,
|
||||
process.env.TEST_HOST
|
||||
).href;
|
||||
}
|
||||
};
|
||||
|
||||
// Config as function
|
||||
if (typeof options.config === 'function') {
|
||||
return function(vm) {
|
||||
return function (vm) {
|
||||
const config = { ...sharedConfig, ...options.config(vm) };
|
||||
|
||||
updateBasePath(config);
|
||||
|
@ -131,7 +135,8 @@ async function docsifyInit(options = {}) {
|
|||
.filter(([url, responseText]) => url && responseText)
|
||||
.map(([url, responseText]) => [
|
||||
// Convert relative to absolute URL
|
||||
new URL(url, settings.config.basePath || TEST_HOST).href,
|
||||
new URL(url, settings.config.basePath || process.env.TEST_HOST)
|
||||
.href,
|
||||
// Strip indentation from responseText
|
||||
stripIndent`${responseText}`,
|
||||
])
|
||||
|
@ -143,11 +148,11 @@ async function docsifyInit(options = {}) {
|
|||
scriptURLs: []
|
||||
.concat(options.scriptURLs || '')
|
||||
.filter(url => url)
|
||||
.map(url => new URL(url, TEST_HOST).href),
|
||||
.map(url => new URL(url, process.env.TEST_HOST).href),
|
||||
styleURLs: []
|
||||
.concat(options.styleURLs || '')
|
||||
.filter(url => url)
|
||||
.map(url => new URL(url, TEST_HOST).href),
|
||||
.map(url => new URL(url, process.env.TEST_HOST).href),
|
||||
};
|
||||
|
||||
// Routes
|
||||
|
@ -325,7 +330,7 @@ async function docsifyInit(options = {}) {
|
|||
elm => elm.outerHTML
|
||||
);
|
||||
} else {
|
||||
htmlArr = await page.$$eval(selector, elms =>
|
||||
htmlArr = await page.evaluateAll(selector, elms =>
|
||||
elms.map(e => e.outerHTML)
|
||||
);
|
||||
}
|
||||
|
@ -350,16 +355,6 @@ async function docsifyInit(options = {}) {
|
|||
}
|
||||
}
|
||||
|
||||
// Debug
|
||||
if (settings._debug) {
|
||||
if (isJSDOM) {
|
||||
// eslint-disable-next-line no-debugger
|
||||
debugger;
|
||||
} else if (isPlaywright) {
|
||||
await jestPlaywright.debug();
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ const defaults = {
|
|||
* @param {Object} options optional parameters
|
||||
* @returns {Promise} promise which resolves to function result
|
||||
*/
|
||||
export function waitForFunction(fn, arg, options = {}) {
|
||||
function waitForFunction(fn, arg, options = {}) {
|
||||
const settings = {
|
||||
...defaults,
|
||||
...options,
|
||||
|
@ -54,7 +54,7 @@ export function waitForFunction(fn, arg, options = {}) {
|
|||
* @param {Object} options optional parameters
|
||||
* @returns {Promise} promise which resolves to first matching element
|
||||
*/
|
||||
export function waitForSelector(cssSelector, options = {}) {
|
||||
function waitForSelector(cssSelector, options = {}) {
|
||||
const settings = {
|
||||
...defaults,
|
||||
...options,
|
||||
|
@ -89,7 +89,7 @@ export function waitForSelector(cssSelector, options = {}) {
|
|||
* @param {Object} options optional parameters
|
||||
* @returns {Promise} promise which resolves to first matching element that contains specified text
|
||||
*/
|
||||
export function waitForText(cssSelector, text, options = {}) {
|
||||
function waitForText(cssSelector, text, options = {}) {
|
||||
const settings = {
|
||||
...defaults,
|
||||
...options,
|
||||
|
@ -124,3 +124,9 @@ export function waitForText(cssSelector, text, options = {}) {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
waitForFunction,
|
||||
waitForSelector,
|
||||
waitForText,
|
||||
};
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
module.exports = require('../unit/.eslintrc');
|
|
@ -2,7 +2,7 @@ const docsifyInit = require('../helpers/docsify-init');
|
|||
|
||||
// Suite
|
||||
// -----------------------------------------------------------------------------
|
||||
describe('Docs Site', function() {
|
||||
describe('Docs Site', function () {
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
test('coverpage renders and is unchanged', async () => {
|
||||
|
|
|
@ -2,13 +2,13 @@ const docsifyInit = require('../helpers/docsify-init');
|
|||
|
||||
// Suite
|
||||
// -----------------------------------------------------------------------------
|
||||
describe('Docsify', function() {
|
||||
describe('Docsify', function () {
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
test('allows $docsify configuration to be a function', async () => {
|
||||
const testConfig = jest.fn(vm => {
|
||||
expect(vm).toBeInstanceOf(Object);
|
||||
expect(vm.constructor.name).toEqual('Docsify');
|
||||
expect(vm.constructor.name).toBe('Docsify');
|
||||
expect(vm.$fetch).toBeInstanceOf(Function);
|
||||
expect(vm.$resetEvents).toBeInstanceOf(Function);
|
||||
expect(vm.route).toBeInstanceOf(Object);
|
||||
|
@ -18,7 +18,7 @@ describe('Docsify', function() {
|
|||
config: testConfig,
|
||||
});
|
||||
|
||||
expect(typeof Docsify).toEqual('object');
|
||||
expect(typeof Docsify).toBe('object');
|
||||
expect(testConfig).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -28,7 +28,7 @@ describe('Docsify', function() {
|
|||
|
||||
return {
|
||||
plugins: [
|
||||
function(hook, vm2) {
|
||||
function (hook, vm2) {
|
||||
expect(vm1).toEqual(vm2);
|
||||
|
||||
expect(hook.init).toBeInstanceOf(Function);
|
||||
|
@ -46,7 +46,7 @@ describe('Docsify', function() {
|
|||
config: testConfig,
|
||||
});
|
||||
|
||||
expect(typeof Docsify).toEqual('object');
|
||||
expect(typeof Docsify).toBe('object');
|
||||
expect(testConfig).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { waitForFunction, waitForText } from '../helpers/wait-for';
|
||||
const { waitForFunction, waitForText } = require('../helpers/wait-for');
|
||||
|
||||
const docsifyInit = require('../helpers/docsify-init');
|
||||
|
||||
// Suite
|
||||
// -----------------------------------------------------------------------------
|
||||
describe('Example Tests', function() {
|
||||
describe('Example Tests', function () {
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
test('Docsify /docs/ site using docsifyInit()', async () => {
|
||||
|
@ -16,7 +16,7 @@ describe('Example Tests', function() {
|
|||
});
|
||||
|
||||
// Verify config options
|
||||
expect(typeof window.$docsify).toEqual('object');
|
||||
expect(typeof window.$docsify).toBe('object');
|
||||
|
||||
// Verify options.markdown content was rendered
|
||||
expect(document.querySelector('#main').textContent).toContain(
|
||||
|
@ -83,7 +83,7 @@ describe('Example Tests', function() {
|
|||
});
|
||||
|
||||
// Verify config options
|
||||
expect(typeof window.$docsify).toEqual('object');
|
||||
expect(typeof window.$docsify).toBe('object');
|
||||
expect(window.$docsify).toHaveProperty('themeColor', 'red');
|
||||
expect(document.querySelector('.app-name').textContent).toContain(
|
||||
'Docsify Name'
|
||||
|
|
|
@ -2,20 +2,20 @@ import initGlobalAPI from '../../src/core/global-api.js';
|
|||
|
||||
// Suite
|
||||
// -----------------------------------------------------------------------------
|
||||
describe('Global APIs', function() {
|
||||
describe('Global APIs', function () {
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
test('APIs are available', () => {
|
||||
initGlobalAPI();
|
||||
|
||||
expect(typeof window.Docsify).toEqual('object');
|
||||
expect(typeof window.Docsify.util).toEqual('object');
|
||||
expect(typeof window.Docsify.dom).toEqual('object');
|
||||
expect(typeof window.Docsify.get).toEqual('function');
|
||||
expect(typeof window.Docsify.slugify).toEqual('function');
|
||||
expect(typeof window.Docsify.version).toEqual('string');
|
||||
expect(typeof window.DocsifyCompiler).toEqual('function');
|
||||
expect(typeof window.marked).toEqual('function');
|
||||
expect(typeof window.Prism).toEqual('object');
|
||||
expect(typeof window.Docsify).toBe('object');
|
||||
expect(typeof window.Docsify.util).toBe('object');
|
||||
expect(typeof window.Docsify.dom).toBe('object');
|
||||
expect(typeof window.Docsify.get).toBe('function');
|
||||
expect(typeof window.Docsify.slugify).toBe('function');
|
||||
expect(typeof window.Docsify.version).toBe('string');
|
||||
expect(typeof window.DocsifyCompiler).toBe('function');
|
||||
expect(typeof window.marked).toBe('function');
|
||||
expect(typeof window.Prism).toBe('object');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@ const docsifyInit = require('../helpers/docsify-init');
|
|||
|
||||
// Suite
|
||||
// -----------------------------------------------------------------------------
|
||||
describe('render', function() {
|
||||
describe('render', function () {
|
||||
// Setup & Teardown
|
||||
// -------------------------------------------------------------------------
|
||||
beforeEach(async () => {
|
||||
|
@ -32,8 +32,8 @@ describe('render', function() {
|
|||
|
||||
// Lists
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('lists', function() {
|
||||
test('as unordered task list', async function() {
|
||||
describe('lists', function () {
|
||||
test('as unordered task list', async function () {
|
||||
const output = window.marked(stripIndent`
|
||||
- [x] Task 1
|
||||
- [ ] Task 2
|
||||
|
@ -45,7 +45,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('as ordered task list', async function() {
|
||||
test('as ordered task list', async function () {
|
||||
const output = window.marked(stripIndent`
|
||||
1. [ ] Task 1
|
||||
2. [x] Task 2
|
||||
|
@ -56,7 +56,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('normal unordered', async function() {
|
||||
test('normal unordered', async function () {
|
||||
const output = window.marked(stripIndent`
|
||||
- [linktext](link)
|
||||
- just text
|
||||
|
@ -67,7 +67,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('unordered with custom start', async function() {
|
||||
test('unordered with custom start', async function () {
|
||||
const output = window.marked(stripIndent`
|
||||
1. first
|
||||
2. second
|
||||
|
@ -82,7 +82,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('nested', async function() {
|
||||
test('nested', async function () {
|
||||
const output = window.marked(stripIndent`
|
||||
- 1
|
||||
- 2
|
||||
|
@ -99,8 +99,8 @@ describe('render', function() {
|
|||
|
||||
// Images
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('images', function() {
|
||||
test('regular', async function() {
|
||||
describe('images', function () {
|
||||
test('regular', async function () {
|
||||
const output = window.marked('![alt text](http://imageUrl)');
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
@ -108,7 +108,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('class', async function() {
|
||||
test('class', async function () {
|
||||
const output = window.marked(
|
||||
"![alt text](http://imageUrl ':class=someCssClass')"
|
||||
);
|
||||
|
@ -118,7 +118,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('id', async function() {
|
||||
test('id', async function () {
|
||||
const output = window.marked(
|
||||
"![alt text](http://imageUrl ':id=someCssID')"
|
||||
);
|
||||
|
@ -128,7 +128,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('no-zoom', async function() {
|
||||
test('no-zoom', async function () {
|
||||
const output = window.marked("![alt text](http://imageUrl ':no-zoom')");
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
@ -136,8 +136,8 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
describe('size', function() {
|
||||
test('width and height', async function() {
|
||||
describe('size', function () {
|
||||
test('width and height', async function () {
|
||||
const output = window.marked(
|
||||
"![alt text](http://imageUrl ':size=WIDTHxHEIGHT')"
|
||||
);
|
||||
|
@ -147,7 +147,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('width', async function() {
|
||||
test('width', async function () {
|
||||
const output = window.marked("![alt text](http://imageUrl ':size=50')");
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
@ -159,8 +159,8 @@ describe('render', function() {
|
|||
|
||||
// Headings
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('headings', function() {
|
||||
test('h1', async function() {
|
||||
describe('headings', function () {
|
||||
test('h1', async function () {
|
||||
const output = window.marked('# h1 tag');
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
@ -168,7 +168,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('h2', async function() {
|
||||
test('h2', async function () {
|
||||
const output = window.marked('## h2 tag');
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
@ -176,7 +176,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('h3', async function() {
|
||||
test('h3', async function () {
|
||||
const output = window.marked('### h3 tag');
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
@ -184,7 +184,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('h4', async function() {
|
||||
test('h4', async function () {
|
||||
const output = window.marked('#### h4 tag');
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
@ -192,7 +192,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('h5', async function() {
|
||||
test('h5', async function () {
|
||||
const output = window.marked('##### h5 tag');
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
@ -200,7 +200,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('h6', async function() {
|
||||
test('h6', async function () {
|
||||
const output = window.marked('###### h6 tag');
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
@ -209,8 +209,8 @@ describe('render', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('link', function() {
|
||||
test('regular', async function() {
|
||||
describe('link', function () {
|
||||
test('regular', async function () {
|
||||
const output = window.marked('[alt text](http://url)');
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
@ -218,7 +218,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('linkrel', async function() {
|
||||
test('linkrel', async function () {
|
||||
// const { docsify } = await init('default', {
|
||||
// externalLinkTarget: '_blank',
|
||||
// externalLinkRel: 'noopener',
|
||||
|
@ -230,7 +230,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('disabled', async function() {
|
||||
test('disabled', async function () {
|
||||
const output = window.marked("[alt text](http://url ':disabled')");
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
@ -238,7 +238,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('target', async function() {
|
||||
test('target', async function () {
|
||||
const output = window.marked("[alt text](http://url ':target=_self')");
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
@ -246,7 +246,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('class', async function() {
|
||||
test('class', async function () {
|
||||
const output = window.marked(
|
||||
"[alt text](http://url ':class=someCssClass')"
|
||||
);
|
||||
|
@ -256,7 +256,7 @@ describe('render', function() {
|
|||
);
|
||||
});
|
||||
|
||||
test('id', async function() {
|
||||
test('id', async function () {
|
||||
const output = window.marked("[alt text](http://url ':id=someCssID')");
|
||||
|
||||
expect(output).toMatchInlineSnapshot(
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
const jestConfig = require('../jest.config.js');
|
||||
|
||||
module.exports = {
|
||||
env: {
|
||||
'jest/globals': true,
|
||||
},
|
||||
extends: ['plugin:jest/recommended', 'plugin:jest/style'],
|
||||
globals: jestConfig.globals,
|
||||
plugins: ['jest'],
|
||||
};
|
|
@ -1,13 +1,18 @@
|
|||
//
|
||||
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';
|
||||
|
||||
// const greet = require('./fixtures/greet');
|
||||
// const getTimeOfDay = require('./fixtures/get-time-of-day');
|
||||
// const getTimeOfDayModule = { getTimeOfDay: getTimeOfDay };
|
||||
|
||||
// Suite
|
||||
// -----------------------------------------------------------------------------
|
||||
describe(`Example Tests`, function() {
|
||||
describe(`Example Tests`, function () {
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('Jest & JSDOM basics', function() {
|
||||
describe('Jest & JSDOM basics', function () {
|
||||
test('dom manipulation (jsdom)', () => {
|
||||
const testText = 'This is a test';
|
||||
const testHTML = `<h1>Test</h1><p>${testText}</p>`;
|
||||
|
@ -19,7 +24,7 @@ describe(`Example Tests`, function() {
|
|||
document.body.classList.add('foo');
|
||||
|
||||
// Test HTML
|
||||
expect(document.body.getAttribute('class')).toEqual('foo');
|
||||
expect(document.body.getAttribute('class')).toBe('foo');
|
||||
expect(document.body.textContent).toMatch(/Test/);
|
||||
expect(document.querySelectorAll('p')).toHaveLength(1);
|
||||
expect(document.querySelector('p').textContent).toBe(testText);
|
||||
|
@ -48,11 +53,11 @@ describe(`Example Tests`, function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Fake Timers', function() {
|
||||
describe('Fake Timers', function () {
|
||||
test('data & time', () => {
|
||||
const fakeDate = new Date().setHours(1);
|
||||
|
||||
jest.useFakeTimers('modern');
|
||||
jest.useFakeTimers();
|
||||
jest.setSystemTime(fakeDate);
|
||||
|
||||
const timeOfDay = getTimeOfDay();
|
||||
|
@ -61,7 +66,7 @@ describe(`Example Tests`, function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Mocks & Spys', function() {
|
||||
describe('Mocks & Spies', 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');
|
||||
|
@ -97,9 +102,9 @@ describe(`Example Tests`, function() {
|
|||
// 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);
|
||||
expect(Math.random()).toBe(0.1);
|
||||
expect(Math.random()).toBe(0.1);
|
||||
expect(Math.random()).toBe(0.1);
|
||||
});
|
||||
|
||||
test('spy on import/require dependency using jest.spyOn()', () => {
|
||||
|
|
|
@ -16,7 +16,7 @@ describe('core/render/utils', () => {
|
|||
test('removeAtag from a link', () => {
|
||||
const result = removeAtag('<a href="www.example.com">content</a>');
|
||||
|
||||
expect(result).toEqual('content');
|
||||
expect(result).toBe('content');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -82,7 +82,7 @@ describe('core/render/tpl', () => {
|
|||
},
|
||||
]);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect(result).toBe(
|
||||
`<ul class="app-sub-sidebar"><li><a class="section-link" href="#/cover?id=basic-usage" title="Basic usage"><span style="color:red">Basic usage</span></a></li><li><a class="section-link" href="#/cover?id=custom-background" title="Custom background">Custom background</a></li><li><a class="section-link" href="#/cover?id=test" title="Test"><img src="/docs/_media/favicon.ico" data-origin="/_media/favicon.ico" alt="ico">Test</a></li></ul>`
|
||||
);
|
||||
});
|
||||
|
@ -96,7 +96,7 @@ describe('core/render/slugify', () => {
|
|||
const result2 = slugify(
|
||||
`Another <span style="font-size: 1.2em" class="foo bar baz">broken <span class="aaa">example</span></span>`
|
||||
);
|
||||
expect(result).toEqual(`bla-bla-bla-`);
|
||||
expect(result2).toEqual(`another-broken-example`);
|
||||
expect(result).toBe(`bla-bla-bla-`);
|
||||
expect(result2).toBe(`another-broken-example`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -27,25 +27,25 @@ describe('router/history/base', () => {
|
|||
test('toURL', () => {
|
||||
const url = history.toURL('guide.md', {}, '/zh-ch/');
|
||||
|
||||
expect(url).toEqual('/zh-ch/guide');
|
||||
expect(url).toBe('/zh-ch/guide');
|
||||
});
|
||||
|
||||
test('toURL with double dot', () => {
|
||||
const url = history.toURL('../README.md', {}, '/zh-ch/');
|
||||
|
||||
expect(url).toEqual('/README');
|
||||
expect(url).toBe('/README');
|
||||
});
|
||||
|
||||
test('toURL child path', () => {
|
||||
const url = history.toURL('config/example.md', {}, '/zh-ch/');
|
||||
|
||||
expect(url).toEqual('/zh-ch/config/example');
|
||||
expect(url).toBe('/zh-ch/config/example');
|
||||
});
|
||||
|
||||
test('toURL absolute path', () => {
|
||||
const url = history.toURL('/README', {}, '/zh-ch/');
|
||||
|
||||
expect(url).toEqual('/README');
|
||||
expect(url).toBe('/README');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -63,7 +63,7 @@ describe('router/history/base', () => {
|
|||
test('toURL', () => {
|
||||
const url = history.toURL('README', {}, '/zh-ch/');
|
||||
|
||||
expect(url).toEqual('/README');
|
||||
expect(url).toBe('/README');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,19 +9,19 @@ describe('router/util', () => {
|
|||
test('resolvePath with filename', () => {
|
||||
const result = resolvePath('hello.md');
|
||||
|
||||
expect(result).toEqual('/hello.md');
|
||||
expect(result).toBe('/hello.md');
|
||||
});
|
||||
|
||||
test('resolvePath with ./', () => {
|
||||
const result = resolvePath('./hello.md');
|
||||
|
||||
expect(result).toEqual('/hello.md');
|
||||
expect(result).toBe('/hello.md');
|
||||
});
|
||||
|
||||
test('resolvePath with ../', () => {
|
||||
const result = resolvePath('test/../hello.md');
|
||||
|
||||
expect(result).toEqual('/hello.md');
|
||||
expect(result).toBe('/hello.md');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|