mirror of
https://gitee.com/docsifyjs/docsify.git
synced 2024-11-29 18:48:14 +08:00
Chore: Clean up server implementation and update test docs (#2316)
- Replace live-server with existing Browsersync dependency as web server - Remove duplicate `index.html` file - Add `build:html` script to generate `/docs/preview.html`
This commit is contained in:
parent
cf61192f9a
commit
1c5a7013f1
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,9 +3,9 @@
|
||||
*.log
|
||||
/_playwright-report
|
||||
/_playwright-results
|
||||
/docs/preview.html
|
||||
/lib
|
||||
/node_modules
|
||||
/themes
|
||||
|
||||
# exceptions
|
||||
!.gitkeep
|
||||
|
42
build/html.js
Normal file
42
build/html.js
Normal file
@ -0,0 +1,42 @@
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import * as url from 'node:url';
|
||||
import prettier from 'prettier';
|
||||
import stripIndent from 'common-tags/lib/stripIndent/index.js';
|
||||
|
||||
const __filename = url.fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const prettierConfig = prettier.resolveConfig.sync(__dirname);
|
||||
|
||||
// Preview
|
||||
// =============================================================================
|
||||
function generatePreview() {
|
||||
const comment = stripIndent`
|
||||
<!--
|
||||
This file is generated by the build/html.js script.
|
||||
Do not edit this file directly.
|
||||
-->
|
||||
`;
|
||||
const srcFile = 'index.html';
|
||||
const srcPath = path.resolve(__dirname, '..', 'docs');
|
||||
const srcHTML = fs.readFileSync(path.resolve(srcPath, srcFile), 'utf8');
|
||||
const outFile = 'preview.html';
|
||||
const outPath = path.resolve(__dirname, '..', 'docs');
|
||||
const outHTML = srcHTML
|
||||
// Append comment
|
||||
.replace(/(<!DOCTYPE html>)/, `${comment}\n$1`)
|
||||
// Modify title
|
||||
.replace(/(<\/title>)/, ' (Preview)$1')
|
||||
// Replace CDN URLs with local paths
|
||||
.replace(/\/\/cdn.jsdelivr.net\/npm\/docsify@4\//g, '/');
|
||||
const formattedHTML = prettier.format(outHTML, {
|
||||
...prettierConfig,
|
||||
filepath: outFile,
|
||||
});
|
||||
|
||||
console.log(`\nBuilding ${outFile} in ${outPath}`);
|
||||
|
||||
fs.writeFileSync(path.resolve(outPath, outFile), formattedHTML);
|
||||
}
|
||||
|
||||
generatePreview();
|
@ -56,19 +56,22 @@
|
||||
width: auto !important;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
(function () {
|
||||
const lang = location.hash.match(/#\/(de-de|es|ru-ru|zh-cn)\//);
|
||||
|
||||
// Set html "lang" attribute based on URL
|
||||
if (lang) {
|
||||
document.documentElement.setAttribute('lang', lang[1]);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">Loading ...</div>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-plugin-carbon@1"></script>
|
||||
<script>
|
||||
// Set html "lang" attribute based on URL
|
||||
const lang = location.hash.match(/#\/(de-de|es|ru-ru|zh-cn)\//);
|
||||
|
||||
if (lang) {
|
||||
document.documentElement.setAttribute('lang', lang[1]);
|
||||
}
|
||||
|
||||
// Docsify configuration
|
||||
window.$docsify = {
|
||||
alias: {
|
||||
@ -184,7 +187,9 @@
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
DocsifyCarbon.create('CEBI6KQE', 'docsifyjsorg'),
|
||||
function () {
|
||||
DocsifyCarbon.create('CEBI6KQE', 'docsifyjsorg');
|
||||
},
|
||||
function (hook, vm) {
|
||||
hook.beforeEach(html => {
|
||||
if (/githubusercontent\.com/.test(vm.route.file)) {
|
||||
@ -214,21 +219,12 @@
|
||||
</script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@4/lib/docsify.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@4/lib/plugins/search.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@4/lib/plugins/ga.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@4/lib/plugins/matomo.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-bash.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-markdown.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-nginx.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-php.min.js"></script>
|
||||
<script>
|
||||
// Public site only
|
||||
if (/docsify/.test(location.host)) {
|
||||
document.write(
|
||||
'<script src="//cdn.jsdelivr.net/npm/docsify@4/lib/plugins/ga.min.js"><\/script>'
|
||||
);
|
||||
document.write(
|
||||
'<script src="//cdn.jsdelivr.net/npm/docsify@4/lib/plugins/matomo.min.js"><\/script>'
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<script src="//cdn.jsdelivr.net/npm/vue@2/dist/vue.min.js"></script>
|
||||
<!-- <script src="//cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script> -->
|
||||
</body>
|
||||
|
190
index.html
190
index.html
@ -1,190 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>docsify</title>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<link rel="stylesheet" href="/themes/vue.css" title="vue" />
|
||||
<link rel="stylesheet" href="/themes/dark.css" title="dark" disabled />
|
||||
<link rel="stylesheet" href="/themes/buble.css" title="buble" disabled />
|
||||
<link rel="stylesheet" href="/themes/pure.css" title="pure" disabled />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/themes/dolphin.css"
|
||||
title="dolphin"
|
||||
disabled
|
||||
/>
|
||||
<style>
|
||||
nav.app-nav li ul {
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
#carbonads {
|
||||
box-shadow: none !important;
|
||||
width: auto !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-plugin-carbon@1"></script>
|
||||
<script>
|
||||
// Set html "lang" attribute based on URL
|
||||
const lang = location.hash.match(/#\/(de-de|es|ru-ru|zh-cn)\//);
|
||||
|
||||
if (lang) {
|
||||
document.documentElement.setAttribute('lang', lang[1]);
|
||||
}
|
||||
|
||||
// Docsify configuration
|
||||
window.$docsify = {
|
||||
alias: {
|
||||
'.*?/awesome':
|
||||
'https://raw.githubusercontent.com/docsifyjs/awesome-docsify/master/README.md',
|
||||
'.*?/changelog':
|
||||
'https://raw.githubusercontent.com/docsifyjs/docsify/master/CHANGELOG.md',
|
||||
'/.*/_navbar.md': '/_navbar.md',
|
||||
'/es/(.*)':
|
||||
'https://raw.githubusercontent.com/docsifyjs/docs-es/master/$1',
|
||||
'/de-de/(.*)':
|
||||
'https://raw.githubusercontent.com/docsifyjs/docs-de/master/$1',
|
||||
'/ru-ru/(.*)':
|
||||
'https://raw.githubusercontent.com/docsifyjs/docs-ru/master/$1',
|
||||
'/zh-cn/(.*)':
|
||||
'https://cdn.jsdelivr.net/gh/docsifyjs/docs-zh@master/$1',
|
||||
},
|
||||
auto2top: true,
|
||||
basePath: '/docs/',
|
||||
coverpage: true,
|
||||
executeScript: true,
|
||||
loadSidebar: true,
|
||||
loadNavbar: true,
|
||||
mergeNavbar: true,
|
||||
maxLevel: 4,
|
||||
subMaxLevel: 2,
|
||||
name: 'docsify',
|
||||
nameLink: {
|
||||
'/es/': '#/es/',
|
||||
'/de-de/': '#/de-de/',
|
||||
'/ru-ru/': '#/ru-ru/',
|
||||
'/zh-cn/': '#/zh-cn/',
|
||||
'/': '#/',
|
||||
},
|
||||
search: {
|
||||
noData: {
|
||||
'/es/': '¡No hay resultados!',
|
||||
'/de-de/': 'Keine Ergebnisse!',
|
||||
'/ru-ru/': 'Никаких результатов!',
|
||||
'/zh-cn/': '没有结果!',
|
||||
'/': 'No results!',
|
||||
},
|
||||
paths: 'auto',
|
||||
placeholder: {
|
||||
'/es/': 'Buscar',
|
||||
'/de-de/': 'Suche',
|
||||
'/ru-ru/': 'Поиск',
|
||||
'/zh-cn/': '搜索',
|
||||
'/': 'Search',
|
||||
},
|
||||
pathNamespaces: ['/es', '/de-de', '/ru-ru', '/zh-cn'],
|
||||
},
|
||||
skipLink: {
|
||||
'/es/': 'Saltar al contenido principal',
|
||||
'/de-de/': 'Ga naar de hoofdinhoud',
|
||||
'/ru-ru/': 'Перейти к основному содержанию',
|
||||
'/zh-cn/': '跳到主要内容',
|
||||
},
|
||||
vueComponents: {
|
||||
'button-counter': {
|
||||
template: /* html */ `<button @click="count += 1">You clicked me {{ count }} times</button>`,
|
||||
data() {
|
||||
return {
|
||||
count: 0,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
vueGlobalOptions: {
|
||||
data() {
|
||||
return {
|
||||
count: 0,
|
||||
message: 'Hello, World!',
|
||||
// Fake API response
|
||||
images: [
|
||||
{ title: 'Image 1', url: 'https://picsum.photos/150?random=1' },
|
||||
{ title: 'Image 2', url: 'https://picsum.photos/150?random=2' },
|
||||
{ title: 'Image 3', url: 'https://picsum.photos/150?random=3' },
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
timeOfDay() {
|
||||
const date = new Date();
|
||||
const hours = date.getHours();
|
||||
|
||||
if (hours < 12) {
|
||||
return 'morning';
|
||||
} else if (hours < 18) {
|
||||
return 'afternoon';
|
||||
} else {
|
||||
return 'evening';
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
hello() {
|
||||
alert(this.message);
|
||||
},
|
||||
},
|
||||
},
|
||||
vueMounts: {
|
||||
'#counter': {
|
||||
data() {
|
||||
return {
|
||||
count: 0,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
DocsifyCarbon.create('CEBI6KQE', 'docsifyjsorg'),
|
||||
function (hook, vm) {
|
||||
hook.beforeEach(html => {
|
||||
if (/githubusercontent\.com/.test(vm.route.file)) {
|
||||
url = vm.route.file
|
||||
.replace('raw.githubusercontent.com', 'github.com')
|
||||
.replace(/\/master/, '/blob/master');
|
||||
} else if (/jsdelivr\.net/.test(vm.route.file)) {
|
||||
url = vm.route.file
|
||||
.replace('cdn.jsdelivr.net/gh', 'github.com')
|
||||
.replace('@master', '/blob/master');
|
||||
} else {
|
||||
url =
|
||||
'https://github.com/docsifyjs/docsify/blob/develop/docs/' +
|
||||
vm.route.file;
|
||||
}
|
||||
const editHtml = '[:memo: Edit Document](' + url + ')\n';
|
||||
return (
|
||||
editHtml +
|
||||
html +
|
||||
'\n\n----\n\n' +
|
||||
'<a href="https://docsify.js.org" target="_blank" style="color: inherit; font-weight: normal; text-decoration: none;">Powered by docsify</a>\n\n' +
|
||||
'<a href="https://vercel.com/?utm_source=docsifyjs&utm_campaign=oss" target="_blank" title="Vercel has given us a Pro account"><img src="/docs/_media/powered-by-vercel.svg" alt="Vercel" width="150"></a>'
|
||||
);
|
||||
});
|
||||
},
|
||||
],
|
||||
};
|
||||
</script>
|
||||
<script src="/lib/docsify.js"></script>
|
||||
<script src="/lib/plugins/search.js"></script>
|
||||
<script src="/lib/plugins/front-matter.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-markdown.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-nginx.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-php.min.js"></script>
|
||||
|
||||
<script src="//cdn.jsdelivr.net/npm/vue@2/dist/vue.min.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,5 +1,7 @@
|
||||
import { TEST_HOST } from './test/config/server.js';
|
||||
import serverConfig from './server.config.js';
|
||||
|
||||
const { hostname, port } = serverConfig.test;
|
||||
const TEST_HOST = `http://${hostname}:${port}`;
|
||||
const sharedConfig = {
|
||||
errorOnDeprecated: true,
|
||||
globalSetup: './test/config/jest.setup.js',
|
||||
@ -11,6 +13,8 @@ const sharedConfig = {
|
||||
testURL: `${TEST_HOST}/_blank.html`,
|
||||
};
|
||||
|
||||
process.env.TEST_HOST = TEST_HOST;
|
||||
|
||||
export default {
|
||||
transform: {},
|
||||
projects: [
|
||||
|
3119
package-lock.json
generated
3119
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@ -24,14 +24,14 @@
|
||||
],
|
||||
"scripts": {
|
||||
"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:css:min": "node build/mincss.js",
|
||||
"build:css": "mkdirp lib/themes && node build/css -o lib/themes",
|
||||
"build:emoji": "node ./build/emoji.js",
|
||||
"build:html": "node ./build/html.js",
|
||||
"build:js": "cross-env NODE_ENV=production node build/build.js",
|
||||
"build:test": "npm run build && npm test",
|
||||
"build": "rimraf lib themes && run-s build:js build:css build:css:min build:cover build:emoji",
|
||||
"css": "node build/css",
|
||||
"dev": "run-p serve watch:*",
|
||||
"build": "rimraf lib themes && run-s build:js build:css build:css:min build:cover build:emoji build:html",
|
||||
"dev": "run-p serve:dev 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",
|
||||
@ -41,19 +41,20 @@
|
||||
"docker:test:integration": "npm run docker:cli -- test:integration",
|
||||
"docker:test:unit": "npm run docker:cli -- test:unit",
|
||||
"docker:test": "npm run docker:cli -- test",
|
||||
"prettier": "prettier . --write",
|
||||
"jest": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"lint": "prettier . --check && eslint .",
|
||||
"postinstall": "opencollective-postinstall",
|
||||
"prepare": "npm run build",
|
||||
"prettier": "prettier . --write",
|
||||
"pub:next": "cross-env RELEASE_TAG=next sh build/release.sh",
|
||||
"pub": "sh build/release.sh",
|
||||
"serve:dev": "npm run build:html && npm run serve -- --dev",
|
||||
"serve": "node server",
|
||||
"test:e2e": "playwright test",
|
||||
"test:integration": "npm run jest -- --selectProjects integration",
|
||||
"test:unit": "npm run jest -- --selectProjects unit",
|
||||
"test": "npm run jest && run-s test:e2e",
|
||||
"jest": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
|
||||
"watch:css": "npm run css -- -o themes -w",
|
||||
"watch:js": "node build/build.js"
|
||||
},
|
||||
@ -105,7 +106,6 @@
|
||||
"husky": "^8.0.3",
|
||||
"jest": "^27.4.7",
|
||||
"lint-staged": "^13.2.2",
|
||||
"live-server": "^1.2.1",
|
||||
"mkdirp": "^3.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.8.8",
|
||||
|
@ -1,4 +1,10 @@
|
||||
import { devices } from '@playwright/test';
|
||||
import serverConfig from './server.config.js';
|
||||
|
||||
const { hostname, port } = serverConfig.test;
|
||||
const TEST_HOST = `http://${hostname}:${port}`;
|
||||
|
||||
process.env.TEST_HOST = TEST_HOST;
|
||||
|
||||
/**
|
||||
* @see https://playwright.dev/docs/test-configuration
|
||||
@ -36,7 +42,7 @@ const config = {
|
||||
// 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('/')`).
|
||||
baseURL: TEST_HOST, // Allow relative page.goto() (e.g. `await page.goto('/')`).
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
|
||||
|
65
server.config.js
Normal file
65
server.config.js
Normal file
@ -0,0 +1,65 @@
|
||||
import * as path from 'node:path';
|
||||
import * as url from 'node:url';
|
||||
|
||||
const __filename = url.fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const defaults = {
|
||||
hostname: '127.0.0.1',
|
||||
notify: false,
|
||||
open: false,
|
||||
rewriteRules: [
|
||||
// Replace remote URLs with local paths
|
||||
{
|
||||
// Changelog
|
||||
match: /https?.*\/CHANGELOG.md/g,
|
||||
replace: '/CHANGELOG.md',
|
||||
},
|
||||
],
|
||||
server: {
|
||||
baseDir: 'docs',
|
||||
index: 'preview.html',
|
||||
routes: {
|
||||
'/changelog.md': path.resolve(__dirname, 'CHANGELOG.md'),
|
||||
'/lib': path.resolve(__dirname, 'lib'),
|
||||
'/node_modules': path.resolve(__dirname, 'node_modules'), // Required for automated Vue tests
|
||||
},
|
||||
},
|
||||
snippet: false,
|
||||
ui: false,
|
||||
};
|
||||
|
||||
export default {
|
||||
// Development (preview, local URLs, watch enabled)
|
||||
dev: {
|
||||
...defaults,
|
||||
files: ['CHANGELOG.md', 'docs/**/*', 'lib/**/*'],
|
||||
port: 3000,
|
||||
open: true,
|
||||
snippet: true,
|
||||
},
|
||||
// Production (index, CDN URLs, watch disabled)
|
||||
prod: {
|
||||
...defaults,
|
||||
port: 8080,
|
||||
server: {
|
||||
...defaults.server,
|
||||
index: 'index.html',
|
||||
},
|
||||
},
|
||||
// Test (preview, local URLs, watch disabled)
|
||||
test: {
|
||||
...defaults,
|
||||
middleware: [
|
||||
// Blank page required for test environment
|
||||
{
|
||||
route: '/_blank.html',
|
||||
handle(req, res, next) {
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.end('');
|
||||
next();
|
||||
},
|
||||
},
|
||||
],
|
||||
port: 4000,
|
||||
},
|
||||
};
|
19
server.js
19
server.js
@ -1,10 +1,13 @@
|
||||
import liveServer from 'live-server';
|
||||
const middleware = [];
|
||||
import { create } from 'browser-sync';
|
||||
import serverConfigs from './server.config.js';
|
||||
|
||||
const params = {
|
||||
port: 3000,
|
||||
watch: ['lib', 'docs', 'themes'],
|
||||
middleware,
|
||||
};
|
||||
const bsServer = create();
|
||||
const args = process.argv.slice(2);
|
||||
const configName =
|
||||
Object.keys(serverConfigs).find(name => args.includes(`--${name}`)) || 'prod';
|
||||
const settings = serverConfigs[configName];
|
||||
|
||||
liveServer.start(params);
|
||||
// prettier-ignore
|
||||
console.log(`\nStarting ${configName} server (${settings.server.index}, watch: ${Boolean(settings.files)})\n`);
|
||||
|
||||
bsServer.init(settings);
|
||||
|
106
test/README.md
106
test/README.md
@ -4,67 +4,79 @@
|
||||
|
||||
- [Jest](https://jestjs.io): A test framework used for assertions, mocks, spies, etc.
|
||||
- [Playwright](https://playwright.dev): A test automation tool for launching browsers and manipulating the DOM.
|
||||
- [Jest-Playwright](https://github.com/playwright-community/jest-playwright): A Jest preset that simplifies using Jest and Playwright together
|
||||
|
||||
## Test files
|
||||
|
||||
- E2E tests are located in `/test/e2e/` and use [Jest](https://jestjs.io) + [Playwright](https://playwright.dev).
|
||||
- Integration tests are located in `/test/integration/` and use [Jest](https://jestjs.io).
|
||||
- Unit tests located in `/test/unit/` and use [Jest](https://jestjs.io).
|
||||
|
||||
## Global Variables
|
||||
|
||||
- `process.env.TEST_HOST`: Test server ip:port
|
||||
- Integration tests are located in `/test/integration/` and use [Jest](https://jestjs.io).
|
||||
- E2E tests are located in `/test/e2e/` and use [Jest](https://jestjs.io) + [Playwright](https://playwright.dev).
|
||||
|
||||
## CLI commands
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
npm run test
|
||||
npm t
|
||||
|
||||
# Run test types
|
||||
npm run test:e2e
|
||||
npm run test:integration
|
||||
npm run test:unit
|
||||
|
||||
# Run test file
|
||||
npm run test -- -i /path/to/file.test.js
|
||||
|
||||
# Run matching test files
|
||||
npm run test -- -i /path/to/*.test.js
|
||||
|
||||
# Run matching test name(s)
|
||||
npm run test -- -t \"describe() or test() name\"
|
||||
|
||||
# Run matching test name(s) in file
|
||||
npm run test -- -i /path/to/file.test.js -t \"describe() or test() name\"
|
||||
|
||||
# Run all example tests
|
||||
npm run test -- -i /test/**/example.test.js
|
||||
|
||||
# Run specific example test file
|
||||
npm run test -- -i /path/to/example.test.js
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Update snapshots for matching test files
|
||||
npm run test -- -u -i /path/to/*.test.js
|
||||
|
||||
# Update snapshots for matching test name(s)
|
||||
npm run test -- -u -t \"describe() or test() name\"
|
||||
|
||||
# Update snapshots for matching test name(s) in file
|
||||
npm run test -- -u -i /path/to/file.test.js -t \"describe() or test() name\"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Start manual test server instance. Useful for previewing test fixtures.
|
||||
# Root: /test/e2e/fixtures/
|
||||
# Routes: /docs, /lib,
|
||||
node ./test/config/server.js --start
|
||||
```
|
||||
|
||||
## Resource
|
||||
### Unit / Integration (Jest)
|
||||
|
||||
- [UI Testing Best Practices](https://github.com/NoriSte/ui-testing-best-practices)
|
||||
- [Using Jest with Playwright](https://playwright.tech/blog/using-jest-with-playwright)
|
||||
```bash
|
||||
# Run test file(s)
|
||||
npm run test:unit -- -i ./path/to/file.test.js
|
||||
npm run test:unit -- -i ./path/to/*.test.js
|
||||
|
||||
# Run test name(s)
|
||||
npm run test:unit -- -t "my test"
|
||||
|
||||
# Run test name(s) in file
|
||||
npm run test:unit -- -i ./path/to/file.test.js -t "my test"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Update snapshots
|
||||
npm run test:unit -- -u
|
||||
|
||||
# Update snapshots for test file(s)
|
||||
npm run test:unit -- -u -i ./path/to/file.test.js
|
||||
npm run test:unit -- -u -i ./path/to/*.test.js
|
||||
|
||||
# Update snapshots for test name(s)
|
||||
npm run test:unit -- -u -t "my test"
|
||||
|
||||
# Update snapshots for test name(s) in file
|
||||
npm run test:unit -- -u -i ./path/to/file.test.js -t "my test"
|
||||
```
|
||||
|
||||
### E2E (Playwright)
|
||||
|
||||
```bash
|
||||
# Run test file(s)
|
||||
npm run test:e2e -- ./path/to/file.test.js
|
||||
npm run test:e2e -- ./path/to/*.test.js
|
||||
|
||||
# Run test name(s)
|
||||
npm run test:e2e -- -g "my test"
|
||||
|
||||
# Run test name(s) in file
|
||||
npm run test:e2e -- ./path/to/file.test.js -g "my test"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Update snapshots
|
||||
npm run test:e2e -- -u
|
||||
|
||||
# Update snapshots for test file(s)
|
||||
npm run test:e2e -- -u ./path/to/file.test.js
|
||||
npm run test:e2e -- -u ./path/to/*.test.js
|
||||
|
||||
# Update snapshots for test name(s)
|
||||
npm run test:e2e -- -u -g "my test"
|
||||
|
||||
# Update snapshots for test name(s) in file
|
||||
npm run test:e2e -- -u ./path/to/file.test.js -g "my test"
|
||||
```
|
||||
|
@ -1,5 +1,5 @@
|
||||
import server from './server.js';
|
||||
import { startServer } from './server.js';
|
||||
|
||||
export default async () => {
|
||||
await server.startAsync();
|
||||
await startServer();
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import server from './server.js';
|
||||
import { stopServer } from './server.js';
|
||||
|
||||
export default async () => {
|
||||
server.stop();
|
||||
stopServer();
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import server from './server.js';
|
||||
import { startServer } from './server.js';
|
||||
|
||||
export default async config => {
|
||||
await server.startAsync();
|
||||
startServer();
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import server from './server.js';
|
||||
import { stopServer } from './server.js';
|
||||
|
||||
export default async config => {
|
||||
server.stop();
|
||||
stopServer();
|
||||
};
|
||||
|
@ -1,136 +1,32 @@
|
||||
import * as process from 'node:process';
|
||||
import { create } from 'browser-sync';
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
import { noop } from '../../src/core/util/core.js';
|
||||
import config from '../../server.config.js';
|
||||
|
||||
const browserSync = create();
|
||||
const bsServer = create();
|
||||
|
||||
const hasStartArg = process.argv.includes('--start');
|
||||
const serverConfig = {
|
||||
hostname: '127.0.0.1',
|
||||
port: hasStartArg ? 3002 : 3001,
|
||||
};
|
||||
export async function startServer() {
|
||||
// Wait for server to start
|
||||
return new Promise(resolve => {
|
||||
const settings = config.test;
|
||||
|
||||
const __filename = url.fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
console.log('\n');
|
||||
|
||||
export const TEST_HOST = `http://${serverConfig.hostname}:${serverConfig.port}`;
|
||||
bsServer.init(settings, () => {
|
||||
// Exit process if specified port is not available. BrowserSync
|
||||
// auto-selects a new port if the specified port is unavailable. This is
|
||||
// problematic for testing and CI/CD.
|
||||
if (bsServer.getOption('port') !== settings.port) {
|
||||
console.log(
|
||||
`\nPort ${settings.port} not available. Exiting process.\n`
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
function startServer(options = {}, cb = noop) {
|
||||
const defaults = {
|
||||
...serverConfig,
|
||||
middleware: [
|
||||
{
|
||||
route: '/_blank.html',
|
||||
handle(req, res, next) {
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.end('');
|
||||
next();
|
||||
},
|
||||
},
|
||||
],
|
||||
notify: false,
|
||||
open: false,
|
||||
rewriteRules: [
|
||||
// Replace docsify-related CDN URLs with local paths
|
||||
{
|
||||
match:
|
||||
/(https?:)?\/\/cdn\.jsdelivr\.net\/npm\/docsify(@\d?\.?\d?\.?\d)?\/lib\//g,
|
||||
replace: '/lib/',
|
||||
},
|
||||
],
|
||||
server: {
|
||||
baseDir: path.resolve(__dirname, '../'),
|
||||
routes: {
|
||||
'/docs': path.resolve(__dirname, '../../docs'),
|
||||
'/docs/changelog.md': './CHANGELOG.md',
|
||||
'/lib': path.resolve(__dirname, '../../lib'),
|
||||
'/node_modules': path.resolve(__dirname, '../../node_modules'),
|
||||
},
|
||||
},
|
||||
snippetOptions: {
|
||||
rule: {
|
||||
match: /<\/body>/i,
|
||||
fn(snippet, match) {
|
||||
// Override changelog alias to load local changelog (see routes)
|
||||
const newSnippet = /* html */ `
|
||||
${snippet.replace(/<script[^>]*/, '$& type="text/plain"')}
|
||||
<script>
|
||||
{
|
||||
const aliasConfig = (window && window.$docsify && window.$docsify.alias) || {};
|
||||
|
||||
// Fix /docs site configuration during tests
|
||||
aliasConfig['.*?/changelog'] = '/changelog.md';
|
||||
|
||||
// Enable BrowserSync snippet
|
||||
document.querySelector('#__bs_script__').removeAttribute('type');
|
||||
}
|
||||
</script>
|
||||
${match}
|
||||
`;
|
||||
|
||||
return newSnippet;
|
||||
},
|
||||
},
|
||||
},
|
||||
ui: false,
|
||||
};
|
||||
|
||||
console.log('\n');
|
||||
|
||||
// Set TEST_HOST environment variable
|
||||
process.env.TEST_HOST = TEST_HOST;
|
||||
|
||||
// Start server
|
||||
browserSync.init(
|
||||
// Config
|
||||
{
|
||||
...defaults,
|
||||
...options,
|
||||
},
|
||||
// Callback
|
||||
cb
|
||||
);
|
||||
}
|
||||
|
||||
async function startServerAsync() {
|
||||
await new Promise((resolve, reject) => {
|
||||
startServer({}, () => {
|
||||
console.log('\n');
|
||||
resolve();
|
||||
resolve(bsServer);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function stopServer() {
|
||||
browserSync.exit();
|
||||
export function stopServer() {
|
||||
bsServer.exit();
|
||||
}
|
||||
|
||||
// Allow starting the test server from the CLI. Useful for viewing test content
|
||||
// like fixtures (/index.html)) and local docs site (/docs) used for testing.
|
||||
if (hasStartArg) {
|
||||
startServer({
|
||||
open: true,
|
||||
port: serverConfig.port,
|
||||
directory: true,
|
||||
startPath: '/docs',
|
||||
});
|
||||
}
|
||||
// Display friendly message about manually starting a server instance
|
||||
else if (isMain(import.meta)) {
|
||||
console.info('Use --start argument to manually start server instance');
|
||||
}
|
||||
|
||||
// Replacement for CommonJS `require.main === module`. https://2ality.com/2022/07/nodejs-esm-main.html
|
||||
function isMain(meta) {
|
||||
if (meta.url.startsWith('file:')) {
|
||||
if (process.argv[1] === __filename) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export default {
|
||||
start: startServer,
|
||||
startAsync: startServerAsync,
|
||||
stop: stopServer,
|
||||
};
|
||||
|
@ -10,7 +10,6 @@ test.describe('Creating a Docsify site (e2e tests in Playwright)', () => {
|
||||
await page.evaluate(() => {
|
||||
window.$docsify = {
|
||||
el: '#app',
|
||||
basePath: '/docs/',
|
||||
themeColor: 'red',
|
||||
};
|
||||
});
|
||||
@ -36,9 +35,6 @@ test.describe('Creating a Docsify site (e2e tests in Playwright)', () => {
|
||||
// Load custom docsify
|
||||
// (See ./helpers/docsifyInit.js for details)
|
||||
await docsifyInit({
|
||||
config: {
|
||||
basePath: '/docs/',
|
||||
},
|
||||
// _logHTML: true,
|
||||
});
|
||||
|
||||
|
@ -4,9 +4,9 @@ import { test, expect } from './fixtures/docsify-init-fixture.js';
|
||||
test.describe('Index file hosting', () => {
|
||||
const sharedOptions = {
|
||||
config: {
|
||||
basePath: '/docs/index.html#/',
|
||||
basePath: '/index.html#/',
|
||||
},
|
||||
testURL: '/docs/index.html#/',
|
||||
testURL: '/index.html#/',
|
||||
};
|
||||
|
||||
test('should serve from index file', async ({ page }) => {
|
||||
|
@ -4,7 +4,6 @@ import _mock, { proxy } from 'xhr-mock';
|
||||
import axios from 'axios';
|
||||
import prettier from 'prettier';
|
||||
import stripIndent from 'common-tags/lib/stripIndent/index.js';
|
||||
// import { TEST_HOST } from '../config/server.js';
|
||||
import { waitForSelector } from './wait-for.js';
|
||||
|
||||
const mock = _mock.default;
|
||||
|
@ -9,7 +9,7 @@ exports[`Docs Site coverpage renders and is unchanged 1`] = `
|
||||
)
|
||||
\\">
|
||||
<div class=\\"mask\\"></div>
|
||||
<div class=\\"cover-main\\"><p><img src=\\"http://127.0.0.1:3001/_media/icon.svg\\" data-origin=\\"_media/icon.svg\\" alt=\\"logo\\"></p><h1 id=\\"docsify-4130\\" tabindex=\\"-1\\"><a href=\\"#/?id=docsify-4130\\" data-id=\\"docsify-4130\\" class=\\"anchor\\"><span>docsify <small>4.13.0</small></span></a></h1><blockquote>
|
||||
<div class=\\"cover-main\\"><p><img src=\\"http://127.0.0.1:4000/_media/icon.svg\\" data-origin=\\"_media/icon.svg\\" alt=\\"logo\\"></p><h1 id=\\"docsify-4130\\" tabindex=\\"-1\\"><a href=\\"#/?id=docsify-4130\\" data-id=\\"docsify-4130\\" class=\\"anchor\\"><span>docsify <small>4.13.0</small></span></a></h1><blockquote>
|
||||
<p>A magical documentation site generator.</p></blockquote>
|
||||
<ul><li>Simple and lightweight</li><li>No statically built html files</li><li>Multiple themes</li></ul><p><a href=\\"https://github.com/docsifyjs/docsify/\\" target=\\"_blank\\" rel=\\"noopener\\">GitHub</a>
|
||||
<a href=\\"#/?id=docsify\\">Getting Started</a></p></div>
|
||||
|
@ -13,7 +13,7 @@ describe('Docs Site', function () {
|
||||
|
||||
await docsifyInit({
|
||||
config: {
|
||||
coverpage: 'docs/_coverpage.md',
|
||||
coverpage: '_coverpage.md',
|
||||
},
|
||||
markdown: {
|
||||
homepage: '# Hello World',
|
||||
@ -32,7 +32,7 @@ describe('Docs Site', function () {
|
||||
test('sidebar renders and is unchanged', async () => {
|
||||
await docsifyInit({
|
||||
config: {
|
||||
loadSidebar: 'docs/_sidebar.md',
|
||||
loadSidebar: '_sidebar.md',
|
||||
},
|
||||
markdown: {
|
||||
homepage: '# Hello World',
|
||||
@ -50,7 +50,7 @@ describe('Docs Site', function () {
|
||||
test('navbar renders and is unchanged', async () => {
|
||||
await docsifyInit({
|
||||
config: {
|
||||
loadNavbar: 'docs/_navbar.md',
|
||||
loadNavbar: '_navbar.md',
|
||||
},
|
||||
markdown: {
|
||||
homepage: '# Hello World',
|
||||
|
@ -4,9 +4,6 @@ import docsifyInit from '../helpers/docsify-init.js';
|
||||
describe('Creating a Docsify site (integration tests in Jest)', function () {
|
||||
test('Docsify /docs/ site using docsifyInit()', async () => {
|
||||
await docsifyInit({
|
||||
config: {
|
||||
basePath: '/docs/',
|
||||
},
|
||||
// _logHTML: true,
|
||||
});
|
||||
|
||||
|
9
vercel.json
Normal file
9
vercel.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/",
|
||||
"destination": "./docs/preview.html",
|
||||
"permanent": true
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user