chore: init e2e testing
69
__tests__/e2e.test.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const assert = require('assert');
|
||||
const jimp = require('jimp');
|
||||
const pixelmatch = require('pixelmatch');
|
||||
const pngjs = require('pngjs');
|
||||
const { delay } = require('./../scripts/util/time');
|
||||
const { pageList } = require('./../scripts/screen.config');
|
||||
const { createScreenshot } = require('../scripts/util/screen');
|
||||
|
||||
const snapshotDir = path.join(__dirname, 'snapshot');
|
||||
const diffDir = path.join(__dirname, 'diff');
|
||||
const { PNG } = pngjs;
|
||||
|
||||
async function diff() {
|
||||
const middlewares = [];
|
||||
const diffRateList = [];
|
||||
pageList.forEach((p) => {
|
||||
middlewares.push(async (ctx = {}, next) => {
|
||||
const { page, port } = ctx;
|
||||
const width = p.w;
|
||||
const height = p.h;
|
||||
await page.setViewport( { width: p.w, height: p.h } );
|
||||
const pageUrl = `http://127.0.0.1:${port}/packages/${p.path || ''}`;
|
||||
await page.goto(pageUrl);
|
||||
await delay(p.delay || 100);
|
||||
const buf = await page.screenshot();
|
||||
|
||||
const snapshotPicPath = parsePicPath(path.join(snapshotDir, p.path));
|
||||
const actual = (await jimp.read(buf)).scale(1).quality(100).bitmap;
|
||||
const expected = (await jimp.read(fs.readFileSync(snapshotPicPath))).bitmap;
|
||||
const diffBuf = new PNG({ width, height });
|
||||
const failedPixel = pixelmatch(expected.data, actual.data, diffBuf.data, actual.width, actual.height);
|
||||
const failRate = failedPixel / (width * height);
|
||||
if (failRate > 0) {
|
||||
(await jimp.read(diffBuf)).scale(1).quality(100).write(parsePicPath(path.join(diffDir, p.path)));
|
||||
}
|
||||
diffRateList.push(failRate);
|
||||
await next();
|
||||
});
|
||||
});
|
||||
await createScreenshot(middlewares, { baseDir: path.join(__dirname, '..') });
|
||||
return diffRateList;
|
||||
}
|
||||
|
||||
function parsePicPath(pagePath) {
|
||||
// const picPath = pagePath.replace(/\.html$/, '.jpg');
|
||||
const picPath = pagePath + '.jpg';
|
||||
return picPath;
|
||||
}
|
||||
|
||||
|
||||
|
||||
describe('Screenshot testing', function() {
|
||||
it('testing...', function(done){
|
||||
this.timeout(1000 * 60 * 2);
|
||||
diff().then((rateList) => {
|
||||
|
||||
assert.ok(Array.isArray(rateList));
|
||||
assert.ok(rateList.length > 0);
|
||||
rateList.forEach((rate) => {
|
||||
console.log('diff-rate =', rate);
|
||||
assert.ok(rate < 0.05);
|
||||
});
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
BIN
__tests__/snapshot/board/examples/features/test.html.jpg
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
__tests__/snapshot/core/examples/features/image.html.jpg
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
__tests__/snapshot/core/examples/features/rect.html.jpg
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
__tests__/snapshot/core/examples/features/svg.html.jpg
Normal file
|
After Width: | Height: | Size: 154 KiB |
BIN
__tests__/snapshot/core/examples/features/text.html.jpg
Normal file
|
After Width: | Height: | Size: 177 KiB |
|
|
@ -26,7 +26,7 @@ function isPointInElement(board, p = {x, y}) {
|
|||
|
||||
function moveElement(board, idx, moveX, moveY) {
|
||||
const data = getData();
|
||||
const scale = getScale();
|
||||
const scale = getScale() || 1;
|
||||
if (data.elements[idx]) {
|
||||
// data.elements[idx].x += (moveX * scale * opts.devicePixelRatio);
|
||||
// data.elements[idx].y += (moveY * scale * opts.devicePixelRatio);
|
||||
|
|
@ -3,6 +3,9 @@ let hasInited = false;
|
|||
|
||||
export function doScale(board, scale) {
|
||||
if (hasInited === true) return;
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
if (scale > 0) {
|
||||
input.value = scale;
|
||||
board.scale(scale);
|
||||
|
|
@ -19,6 +22,9 @@ export function doScale(board, scale) {
|
|||
}
|
||||
|
||||
export function getScale() {
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
let val = 1;
|
||||
if (input.value * 1 > 0) {
|
||||
val = input.value * 1;
|
||||
|
|
@ -4,6 +4,9 @@ let hasInited = false;
|
|||
|
||||
export function doScroll(board, conf = {}) {
|
||||
if (hasInited === true) return;
|
||||
if (!(inputX && inputY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (conf.scrollX >= 0) {
|
||||
inputX.value = conf.scrollX;
|
||||
29
packages/board/examples/features/test.html
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<html>
|
||||
<head>
|
||||
<style></style>
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
|
||||
<style>
|
||||
html,body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#mount canvas {
|
||||
border-right: 1px solid #aaaaaa40;
|
||||
border-bottom: 1px solid #aaaaaa40;
|
||||
background-image:
|
||||
linear-gradient(#aaaaaa40 1px, transparent 0),
|
||||
linear-gradient(90deg, #aaaaaa40 1px, transparent 0),
|
||||
linear-gradient(#aaa 1px, transparent 0),
|
||||
linear-gradient(90deg, #aaa 1px, transparent 0);
|
||||
background-size: 10px 10px, 10px 10px, 50px 50px, 50px 50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="mount"></div>
|
||||
|
||||
<script src="./../../dist/index.global.js"></script>
|
||||
<script type="module" src="./main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import dataRect from './rect.js';
|
||||
import dataImage from './image.js';
|
||||
import dataSVG from './svg.js';
|
||||
import dataText from './text.js';
|
||||
|
||||
const url = new URLSearchParams(window.location.search);
|
||||
|
||||
const dataMap = {
|
||||
'rect': dataRect,
|
||||
'image': dataImage,
|
||||
'svg': dataSVG,
|
||||
'text': dataText
|
||||
}
|
||||
|
||||
export function getData() {
|
||||
return dataMap[url.get('data')] || dataMap['rect'];
|
||||
}
|
||||
25
packages/core/examples/features/image.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<html>
|
||||
<head>
|
||||
<style></style>
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
|
||||
<link rel="stylesheet" href="./css/index.css" />
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; }
|
||||
.dashboard .row { margin: 0 }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="dashboard">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div id="mount"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="./../../dist/index.global.js"></script>
|
||||
<script type="module" src="./lib/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
</div>
|
||||
|
||||
|
||||
<script src="./../dist/index.global.js"></script>
|
||||
<script type="module" src="./main.js"></script>
|
||||
<script src="./../../dist/index.global.js"></script>
|
||||
<script type="module" src="./lib/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -15,7 +15,7 @@ const data = {
|
|||
// angle: 30,
|
||||
// angle: 0,
|
||||
desc: {
|
||||
src: './images/computer.png',
|
||||
src: './../images/computer.png',
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -30,7 +30,7 @@ const data = {
|
|||
borderColor: '#bd0b64',
|
||||
type: 'image',
|
||||
desc: {
|
||||
src: './images/chart.png',
|
||||
src: './../images/chart.png',
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -42,7 +42,7 @@ const data = {
|
|||
type: 'image',
|
||||
angle: 80,
|
||||
desc: {
|
||||
src: './images/phone.png',
|
||||
src: './../images/phone.png',
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -53,7 +53,7 @@ const data = {
|
|||
h: 100,
|
||||
type: 'image',
|
||||
desc: {
|
||||
src: './images/building-001.png',
|
||||
src: './../images/building-001.png',
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -64,7 +64,7 @@ const data = {
|
|||
h: 100,
|
||||
type: 'image',
|
||||
desc: {
|
||||
src: './images/building-002.png',
|
||||
src: './../images/building-002.png',
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -75,7 +75,7 @@ const data = {
|
|||
h: 100,
|
||||
type: 'image',
|
||||
desc: {
|
||||
src: './images/building-003.png',
|
||||
src: './../images/building-003.png',
|
||||
}
|
||||
}
|
||||
]
|
||||
42
packages/core/examples/features/lib/data/index.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import dataRect from './rect.js';
|
||||
import dataImage from './image.js';
|
||||
import dataSVG from './svg.js';
|
||||
import dataText from './text.js';
|
||||
|
||||
const url = new URLSearchParams(window.location.search);
|
||||
|
||||
const dataMap = {
|
||||
'rect': dataRect,
|
||||
'image': dataImage,
|
||||
'svg': dataSVG,
|
||||
'text': dataText
|
||||
}
|
||||
|
||||
export function getData() {
|
||||
return dataMap[getPageName()] || dataMap[url.get('data')] || dataMap['rect'];
|
||||
}
|
||||
|
||||
function getPageName() {
|
||||
// const pathname = window.location.pathname || '';
|
||||
// const reg = /(?<pageName>[\w+]{1,})\.html$/;
|
||||
// const page = reg.exec(pathname)?.groups?.pageName || '';
|
||||
// return page;
|
||||
|
||||
const pathname = window.location.pathname || '';
|
||||
const list = pathname.split('/');
|
||||
let pageName = list.pop() || '';
|
||||
pageName = pageName.replace(/\.html$/ig, '');
|
||||
return pageName;
|
||||
|
||||
// return getQueryString('data') || 'rect';
|
||||
}
|
||||
|
||||
|
||||
// function getQueryString(name) {
|
||||
// let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
|
||||
// let r = window.location.search.substr(1).match(reg);
|
||||
// if (r != null) {
|
||||
// return decodeURIComponent(r[2]);
|
||||
// };
|
||||
// return null;
|
||||
// }
|
||||
|
|
@ -5,6 +5,7 @@ let hasInited = false;
|
|||
|
||||
export function doElemens(core) {
|
||||
if (hasInited === true) return;
|
||||
if (!dom) return;
|
||||
renderElemens(core);
|
||||
listenElements(core);
|
||||
}
|
||||
|
|
@ -1,16 +1,11 @@
|
|||
import { getData } from './lib/data/index.js';
|
||||
import { doScale } from './lib/scale.js';
|
||||
import { doScroll } from './lib/scroll.js';
|
||||
import { doElemens } from './lib/element.js';
|
||||
import { getData } from './data/index.js';
|
||||
import { doScale } from './scale.js';
|
||||
import { doScroll } from './scroll.js';
|
||||
import { doElemens } from './element.js';
|
||||
|
||||
const { Core } = window.iDraw;
|
||||
const data = getData();
|
||||
const mount = document.querySelector('#mount');
|
||||
// const defaultConf = {
|
||||
// scale: 0.8,
|
||||
// scrollX: 100,
|
||||
// scrollY: 50,
|
||||
// }
|
||||
|
||||
const defaultConf = {
|
||||
scale: 1,
|
||||
|
|
@ -23,9 +18,11 @@ const core = new Core(mount, {
|
|||
devicePixelRatio: 4
|
||||
});
|
||||
|
||||
console.log('core ===', core);
|
||||
|
||||
core.setData(data);
|
||||
core.draw();
|
||||
|
||||
doScale(core, defaultConf.scale);
|
||||
doScroll(core, defaultConf);
|
||||
doElemens(core);
|
||||
|
||||
|
|
@ -3,6 +3,7 @@ let hasInited = false;
|
|||
|
||||
export function doScale(core, scale) {
|
||||
if (hasInited === true) return;
|
||||
if (!input) return;
|
||||
if (scale > 0) {
|
||||
input.value = scale;
|
||||
core.scale(scale);
|
||||
|
|
@ -3,7 +3,8 @@ const inputY = document.querySelector('#scrollY');
|
|||
let hasInited = false;
|
||||
|
||||
export function doScroll(core, conf = {}) {
|
||||
if (hasInited === true) return;
|
||||
if (hasInited === true) return;
|
||||
if (!(inputY && inputX)) return;
|
||||
|
||||
if (conf.scrollX >= 0) {
|
||||
inputX.value = conf.scrollX;
|
||||
25
packages/core/examples/features/rect.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<html>
|
||||
<head>
|
||||
<style></style>
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
|
||||
<link rel="stylesheet" href="./css/index.css" />
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; }
|
||||
.dashboard .row { margin: 0 }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="dashboard">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div id="mount"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="./../../dist/index.global.js"></script>
|
||||
<script type="module" src="./lib/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
25
packages/core/examples/features/svg.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<html>
|
||||
<head>
|
||||
<style></style>
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
|
||||
<link rel="stylesheet" href="./css/index.css" />
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; }
|
||||
.dashboard .row { margin: 0 }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="dashboard">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div id="mount"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="./../../dist/index.global.js"></script>
|
||||
<script type="module" src="./lib/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
25
packages/core/examples/features/text.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<html>
|
||||
<head>
|
||||
<style></style>
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
|
||||
<link rel="stylesheet" href="./css/index.css" />
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; }
|
||||
.dashboard .row { margin: 0 }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="dashboard">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div id="mount"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="./../../dist/index.global.js"></script>
|
||||
<script type="module" src="./lib/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 222 KiB After Width: | Height: | Size: 222 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 124 KiB |
|
|
@ -1,7 +1,10 @@
|
|||
const pageList = [
|
||||
// { path: 'paint/examples/path/draw.html', w: 600, h: 600, delay: 200 },
|
||||
// { path: 'paint/examples/path/play.html', w: 600, h: 600, delay: 8000 },
|
||||
{ path: 'drag-core/examples/demo.html', w: 500, h: 1000, delay: 2000 },
|
||||
{ path: 'board/examples/features/test.html', w: 600, h: 400, delay: 1000 },
|
||||
{ path: 'core/examples/features/rect.html', w: 600, h: 400, delay: 1000 },
|
||||
{ path: 'core/examples/features/text.html', w: 600, h: 400, delay: 1000 },
|
||||
{ path: 'core/examples/features/svg.html', w: 600, h: 400, delay: 1000 },
|
||||
{ path: 'core/examples/features/image.html', w: 600, h: 400, delay: 1000 },
|
||||
// { path: 'core/examples/test.html', w: 600, h: 600, delay: 8000 },
|
||||
]
|
||||
|
||||
module.exports = {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const jimp = require('jimp');
|
|||
const path = require('path');
|
||||
const { delay } = require('./util/time');
|
||||
const { createScreenshot } = require('./util/screen');
|
||||
const { removeFullDir } = require('./util/file');
|
||||
const { pageList } = require('./screen.config');
|
||||
|
||||
const snapshotDir = path.join(__dirname, '..', '__tests__', 'snapshot');
|
||||
|
|
@ -9,13 +10,18 @@ const snapshotDir = path.join(__dirname, '..', '__tests__', 'snapshot');
|
|||
main();
|
||||
|
||||
async function main() {
|
||||
removeFullDir(snapshotDir);
|
||||
const middlewares = [];
|
||||
pageList.forEach((p) => {
|
||||
middlewares.push(async (ctx = {}, next) => {
|
||||
const { page, port } = ctx;
|
||||
await page.setViewport( { width: p.w, height: p.h } );
|
||||
const pageUrl = `http://127.0.0.1:${port}/packages/${p.path || ''}`;
|
||||
await page.goto(pageUrl);
|
||||
const result = await page.goto(pageUrl);
|
||||
if (result.status() === 404) {
|
||||
console.error(`404 Not Found: ${pageUrl}`)
|
||||
throw Error('404 status code found in result')
|
||||
}
|
||||
await delay(p.delay || 100);
|
||||
const buf = await page.screenshot();
|
||||
(await jimp.read(buf)).scale(1).quality(100).write(createPicPath(p.path));
|
||||
|
|
@ -28,7 +34,7 @@ async function main() {
|
|||
|
||||
function createPicPath(pagePath) {
|
||||
let picPath = path.join(snapshotDir, pagePath);
|
||||
picPath = picPath.replace(/\.html$/, '.jpg');
|
||||
picPath = picPath + '.jpg'; // picPath.replace(/\.html$/, '.jpg');
|
||||
return picPath;
|
||||
}
|
||||
|
||||
|
|
|
|||
26
scripts/util/file.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function removeFullDir(dirPath) {
|
||||
let files = [];
|
||||
if (fs.existsSync(dirPath)) {
|
||||
files = fs.readdirSync(dirPath);
|
||||
files.forEach((filename) => {
|
||||
let curPath = path.join(dirPath, filename);
|
||||
const stat = fs.statSync(curPath);
|
||||
if(stat.isDirectory()) {
|
||||
removeFullDir(curPath);
|
||||
} else if (stat.isFile()) {
|
||||
// fs.unlinkSync(curPath);
|
||||
fs.rmSync(curPath);
|
||||
} else {
|
||||
fs.unlinkSync(curPath);
|
||||
}
|
||||
});
|
||||
fs.rmdirSync(dirPath);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
removeFullDir,
|
||||
}
|
||||