mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Capture screenshots while running karma tests
This commit is contained in:
parent
a41ba8852f
commit
23b6f29ecf
@ -163,8 +163,7 @@ module.exports = function(config) {
|
|||||||
'/dist': `http://localhost:${port}/base/dist`,
|
'/dist': `http://localhost:${port}/base/dist`,
|
||||||
'/node_modules': `http://localhost:${port}/base/node_modules`,
|
'/node_modules': `http://localhost:${port}/base/node_modules`,
|
||||||
'/tests': `http://localhost:${port}/base/tests`,
|
'/tests': `http://localhost:${port}/base/tests`,
|
||||||
'/assets': `http://localhost:${port}/base/tests/assets`,
|
'/assets': `http://localhost:${port}/base/tests/assets`
|
||||||
'/screenshot': `http://localhost:8081/screenshot`,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
client: {
|
client: {
|
||||||
|
@ -1,10 +1,27 @@
|
|||||||
|
const Server = require('karma').Server;
|
||||||
|
const cfg = require('karma').config;
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const karmaConfig = cfg.parseConfig(path.resolve('./karma.conf.js'));
|
||||||
|
const server = new Server(karmaConfig, (exitCode) => {
|
||||||
|
console.log('Karma has exited with ' + exitCode);
|
||||||
|
process.exit(exitCode)
|
||||||
|
});
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
|
const cors = require('cors');
|
||||||
const filenamifyUrl = require('filenamify-url');
|
const filenamifyUrl = require('filenamify-url');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
app.use(cors());
|
||||||
|
app.use(function(req, res, next) {
|
||||||
|
// IE9 doesn't set headers for cross-domain ajax requests
|
||||||
|
if(typeof(req.headers['content-type']) === 'undefined'){
|
||||||
|
req.headers['content-type'] = "application/json";
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
app.use(
|
app.use(
|
||||||
bodyParser.json({
|
bodyParser.json({
|
||||||
limit: '15mb',
|
limit: '15mb',
|
||||||
@ -20,7 +37,7 @@ const writeScreenshot = (buffer, body) => {
|
|||||||
{replacement: '-'}
|
{replacement: '-'}
|
||||||
)}!${body.platform.name}-${body.platform.version}.png`;
|
)}!${body.platform.name}-${body.platform.version}.png`;
|
||||||
|
|
||||||
fs.writeFileSync(path.resolve(__dirname, '../tests/results/', filename), buffer);
|
fs.writeFileSync(path.resolve(__dirname, './tests/results/', filename), buffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
app.post('/screenshot', (req, res) => {
|
app.post('/screenshot', (req, res) => {
|
||||||
@ -65,5 +82,7 @@ app.use((error, req, res, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const listener = app.listen(8081, () => {
|
const listener = app.listen(8081, () => {
|
||||||
console.log(listener.address().port);
|
server.start();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
|||||||
"body-parser": "1.17.2",
|
"body-parser": "1.17.2",
|
||||||
"chai": "4.1.1",
|
"chai": "4.1.1",
|
||||||
"chromeless": "^1.2.0",
|
"chromeless": "^1.2.0",
|
||||||
|
"cors": "2.8.4",
|
||||||
"eslint": "4.2.0",
|
"eslint": "4.2.0",
|
||||||
"eslint-plugin-flowtype": "2.35.0",
|
"eslint-plugin-flowtype": "2.35.0",
|
||||||
"eslint-plugin-prettier": "2.1.2",
|
"eslint-plugin-prettier": "2.1.2",
|
||||||
@ -62,7 +63,7 @@
|
|||||||
"flow": "flow",
|
"flow": "flow",
|
||||||
"lint": "eslint src/**",
|
"lint": "eslint src/**",
|
||||||
"test": "npm run flow && npm run lint && npm run karma",
|
"test": "npm run flow && npm run lint && npm run karma",
|
||||||
"karma": "karma start",
|
"karma": "node karma",
|
||||||
"watch": "webpack --progress --colors --watch"
|
"watch": "webpack --progress --colors --watch"
|
||||||
},
|
},
|
||||||
"homepage": "https://html2canvas.hertzen.com",
|
"homepage": "https://html2canvas.hertzen.com",
|
||||||
|
11
src/Clone.js
11
src/Clone.js
@ -37,7 +37,7 @@ export class DocumentCloner {
|
|||||||
if (backgroundImage.method === 'url') {
|
if (backgroundImage.method === 'url') {
|
||||||
return this.imageLoader
|
return this.imageLoader
|
||||||
.inlineImage(backgroundImage.args[0])
|
.inlineImage(backgroundImage.args[0])
|
||||||
.then(src => (src ? `url("${src}")` : 'none'));
|
.then(img => (img ? `url("${img.src}")` : 'none'));
|
||||||
}
|
}
|
||||||
return Promise.resolve(
|
return Promise.resolve(
|
||||||
`${backgroundImage.prefix}${backgroundImage.method}(${backgroundImage.args.join(
|
`${backgroundImage.prefix}${backgroundImage.method}(${backgroundImage.args.join(
|
||||||
@ -54,9 +54,12 @@ export class DocumentCloner {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (node instanceof HTMLImageElement) {
|
if (node instanceof HTMLImageElement) {
|
||||||
this.imageLoader.inlineImage(node.src).then(src => {
|
this.imageLoader.inlineImage(node.src).then(img => {
|
||||||
if (src && node instanceof HTMLImageElement) {
|
if (img && node instanceof HTMLImageElement && node.parentNode) {
|
||||||
node.src = src;
|
node.parentNode.replaceChild(
|
||||||
|
copyCSSStyles(node.style, img.cloneNode(false)),
|
||||||
|
node
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,9 @@ export default class ImageLoader<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inlineImage(src: string): Promise<string> {
|
inlineImage(src: string): Promise<Image> {
|
||||||
if (isInlineImage(src)) {
|
if (isInlineImage(src)) {
|
||||||
return Promise.resolve(src);
|
return loadImage(src, this.options.imageTimeout || 0);
|
||||||
}
|
}
|
||||||
if (this.hasImageInCache(src)) {
|
if (this.hasImageInCache(src)) {
|
||||||
return this.cache[src];
|
return this.cache[src];
|
||||||
@ -61,7 +61,7 @@ export default class ImageLoader<T> {
|
|||||||
return this.xhrImage(src);
|
return this.xhrImage(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
xhrImage(src: string): Promise<string> {
|
xhrImage(src: string): Promise<Image> {
|
||||||
this.cache[src] = new Promise((resolve, reject) => {
|
this.cache[src] = new Promise((resolve, reject) => {
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.onreadystatechange = () => {
|
xhr.onreadystatechange = () => {
|
||||||
@ -87,7 +87,7 @@ export default class ImageLoader<T> {
|
|||||||
}
|
}
|
||||||
xhr.open('GET', src, true);
|
xhr.open('GET', src, true);
|
||||||
xhr.send();
|
xhr.send();
|
||||||
});
|
}).then(src => loadImage(src, this.options.imageTimeout || 0));
|
||||||
|
|
||||||
return this.cache[src];
|
return this.cache[src];
|
||||||
}
|
}
|
||||||
@ -196,3 +196,24 @@ const isInlineBase64Image = (src: string): boolean => INLINE_BASE64.test(src);
|
|||||||
|
|
||||||
const isSVG = (src: string): boolean =>
|
const isSVG = (src: string): boolean =>
|
||||||
src.substr(-3).toLowerCase() === 'svg' || INLINE_SVG.test(src);
|
src.substr(-3).toLowerCase() === 'svg' || INLINE_SVG.test(src);
|
||||||
|
|
||||||
|
const loadImage = (src: string, timeout: number) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => resolve(img);
|
||||||
|
img.onerror = reject;
|
||||||
|
img.src = src;
|
||||||
|
if (img.complete === true) {
|
||||||
|
// Inline XML images may fail to parse, throwing an Error later on
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve(img);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
if (timeout) {
|
||||||
|
setTimeout(
|
||||||
|
() => reject(__DEV__ ? `Timed out (${timeout}ms) loading image` : ''),
|
||||||
|
timeout
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
export const contains = (bit: number, value: number): boolean => (bit & value) !== 0;
|
export const contains = (bit: number, value: number): boolean => (bit & value) !== 0;
|
||||||
|
|
||||||
export const copyCSSStyles = (style: CSSStyleDeclaration, target: HTMLElement): void => {
|
export const copyCSSStyles = (style: CSSStyleDeclaration, target: HTMLElement): HTMLElement => {
|
||||||
// Edge does not provide value for cssText
|
// Edge does not provide value for cssText
|
||||||
for (let i = style.length - 1; i >= 0; i--) {
|
for (let i = style.length - 1; i >= 0; i--) {
|
||||||
const property = style.item(i);
|
const property = style.item(i);
|
||||||
@ -12,6 +12,7 @@ export const copyCSSStyles = (style: CSSStyleDeclaration, target: HTMLElement):
|
|||||||
target.style.setProperty(property, style.getPropertyValue(property));
|
target.style.setProperty(property, style.getPropertyValue(property));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return target;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SMALL_IMAGE =
|
export const SMALL_IMAGE =
|
||||||
|
@ -32,11 +32,12 @@ export type Options = {
|
|||||||
offsetY: number
|
offsetY: number
|
||||||
};
|
};
|
||||||
|
|
||||||
const html2canvas = (element: HTMLElement, config: Options = {}): Promise<*> => {
|
const html2canvas = (element: HTMLElement, conf: ?Options): Promise<*> => {
|
||||||
if (typeof console === 'object' && typeof console.log === 'function') {
|
if (typeof console === 'object' && typeof console.log === 'function') {
|
||||||
console.log(`html2canvas ${__VERSION__}`);
|
console.log(`html2canvas ${__VERSION__}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const config = conf || {};
|
||||||
const logger = new Logger();
|
const logger = new Logger();
|
||||||
|
|
||||||
const ownerDocument = element.ownerDocument;
|
const ownerDocument = element.ownerDocument;
|
||||||
|
@ -81,6 +81,7 @@ const assertPath = (result, expected, desc) => {
|
|||||||
.forEach(url => {
|
.forEach(url => {
|
||||||
describe(url, function() {
|
describe(url, function() {
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
|
this.retries(2);
|
||||||
const windowWidth = 800;
|
const windowWidth = 800;
|
||||||
const windowHeight = 600;
|
const windowHeight = 600;
|
||||||
const testContainer = document.createElement('iframe');
|
const testContainer = document.createElement('iframe');
|
||||||
@ -334,13 +335,15 @@ const assertPath = (result, expected, desc) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// window.__karma__
|
if (window.__karma__) {
|
||||||
if (false) {
|
|
||||||
const MAX_CHUNK_SIZE = 75000;
|
const MAX_CHUNK_SIZE = 75000;
|
||||||
|
|
||||||
const sendScreenshot = (tries, body, url) => {
|
const sendScreenshot = (tries, body, server) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr =
|
||||||
|
'withCredentials' in new XMLHttpRequest()
|
||||||
|
? new XMLHttpRequest()
|
||||||
|
: new XDomainRequest();
|
||||||
|
|
||||||
xhr.onload = () => {
|
xhr.onload = () => {
|
||||||
if (
|
if (
|
||||||
@ -354,9 +357,9 @@ const assertPath = (result, expected, desc) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// xhr.onerror = reject;
|
xhr.onerror = reject;
|
||||||
|
|
||||||
xhr.open('POST', url, true);
|
xhr.open('POST', server, true);
|
||||||
xhr.send(body);
|
xhr.send(body);
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
if (tries > 0) {
|
if (tries > 0) {
|
||||||
@ -385,7 +388,7 @@ const assertPath = (result, expected, desc) => {
|
|||||||
version: platform.version
|
version: platform.version
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
'/screenshot/chunk'
|
'http://localhost:8081/screenshot/chunk'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -404,7 +407,7 @@ const assertPath = (result, expected, desc) => {
|
|||||||
version: platform.version
|
version: platform.version
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
'/screenshot'
|
'http://localhost:8081/screenshot'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user