create puppeteer setup

This commit is contained in:
Rene
2020-09-05 00:24:22 +02:00
parent a94c9e46ca
commit e11e36531f
42 changed files with 1289 additions and 97 deletions
+1
View File
@@ -1,4 +1,5 @@
node_modules
coverage
dist
build
types
+6 -1
View File
@@ -58,7 +58,6 @@ module.exports = {
files: ['*.test.*'],
rules: {
'no-restricted-syntax': 'off',
'no-param-reassign': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/ban-types': 'off',
@@ -71,6 +70,12 @@ module.exports = {
'no-empty-function': 'off',
'no-new-func': 'off',
},
globals: {
page: true,
browser: true,
context: true,
jestPuppeteer: true,
},
},
{
files: ['rollup.config.*'],
+1
View File
@@ -5,6 +5,7 @@ node_modules/
# generated
coverage/
build/
# local env files
.env.local
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
browser: 'chromium',
browserContext: 'incognito',
};
+101
View File
@@ -0,0 +1,101 @@
const path = require('path');
const del = require('del');
const rollup = require('rollup');
const babel = require('@babel/core');
const PuppeteerEnvironment = require('jest-environment-puppeteer');
const resolve = require('./resolve.config.json');
const rollupInputFile = 'index';
const rollupOutputFile = 'index';
const rollupOutputDir = 'build';
const rollupNodeEnv = 'build';
const getRollupInfos = (testPath) => {
const projectRootPath = path.resolve(__dirname, resolve.projectRoot);
const testDir = path.dirname(testPath);
const input = path.resolve(testDir, rollupInputFile);
const dist = path.resolve(testDir, rollupOutputDir);
const file = rollupOutputFile;
return {
projectRootPath,
input,
dist,
file,
};
};
const rollupTest = async (testPath) => {
const { projectRootPath, input, dist, file } = getRollupInfos(testPath);
const testPathSplit = path.relative(projectRootPath, testPath).split(path.sep);
if (testPathSplit.length > 0) {
const env = process.env.NODE_ENV;
const project = testPathSplit[0];
const { code: rollupConfigCode } = await babel.transformFileSync('./rollup.config.js', {});
process.env.NODE_ENV = rollupNodeEnv;
// eslint-disable-next-line no-eval
let rollupConfig = await eval(rollupConfigCode)(
{ 'config-project': project },
{
input,
dist,
file,
types: null,
minVersions: false,
esmBuild: false,
sourcemap: false,
},
true
);
if (!Array.isArray(rollupConfig)) {
rollupConfig = [rollupConfig];
}
for (let i = 0; i < rollupConfig.length; i++) {
const inputConfig = rollupConfig[i];
let { output } = inputConfig;
// eslint-disable-next-line no-await-in-loop
const bundle = await rollup.rollup(inputConfig);
if (!Array.isArray(output)) {
output = [output];
}
for (let v = 0; v < output.length; v++) {
const outputConfig = output[i];
// eslint-disable-next-line no-await-in-loop
await bundle.write(outputConfig);
}
}
process.env.NODE_ENV = env;
}
};
const cleanRollupTest = async (testPath) => {
const { dist } = getRollupInfos(testPath);
await del(dist);
};
class CustomEnvironment extends PuppeteerEnvironment {
constructor(config, context) {
super(config, context);
this.ctx = context;
}
async setup() {
await rollupTest(this.ctx.testPath);
await super.setup();
}
async teardown() {
await cleanRollupTest(this.ctx.testPath);
await super.teardown();
}
}
module.exports = CustomEnvironment;
+8 -20
View File
@@ -18,26 +18,14 @@ module.exports = {
{
...base,
displayName: 'jsdom',
testMatch: ['**/__tests__/jsdom/**/*.test.[jt]s?(x)'],
},
{
...base,
preset: 'jest-puppeteer',
displayName: 'puppeteer',
testMatch: ['**/__tests__/puppeteer/**/*.test.[jt]s?(x)'],
testEnvironment: './jest-puppeteer.env.js',
},
// {
// ...base,
// displayName: 'puppeteer',
// globalSetup: './puppeteer.setup.js',
// globalTeardown: './puppeteer.teardown.js',
// testEnvironment: './puppeteer.env.js',
// testMatch: ['**/tests/puppeteer/**/*.[jt]s?(x)'],
// transform: {
// '^.+\\.[jt]sx?$': 'babel-jest',
// '^.+\\.html?$': './jest.html.loader.js',
// },
// globals: {
// async createPage(glob, html, funcs) {
// const page = await glob.__BROWSER__.newPage();
// await page.exposeFunction('evalVar', funcs);
// await page.setContent(fs.readFileSync('./puppeteer.html', 'utf8').replace('{{content}}', html));
// return page;
// },
// },
// },
],
};
+1061
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -13,6 +13,7 @@
"@rollup/plugin-node-resolve": "^8.4.0",
"@rollup/plugin-typescript": "^5.0.2",
"@types/jest": "^25.2.3",
"@types/jest-environment-puppeteer": "^4.3.2",
"@types/puppeteer": "^3.0.1",
"@typescript-eslint/eslint-plugin": "^3.7.0",
"@typescript-eslint/parser": "^3.7.0",
@@ -32,6 +33,7 @@
"eslint-plugin-react": "^7.20.3",
"eslint-plugin-react-hooks": "^4.0.8",
"jest": "^26.0.1",
"jest-puppeteer": "^4.4.0",
"mkdirp": "^1.0.4",
"prettier": "^2.0.5",
"prettier-eslint": "^11.0.0",
@@ -0,0 +1,9 @@
describe('Google', () => {
beforeAll(async () => {
await page.goto('https://google.com');
});
it('should be titled "Google"', async () => {
await expect(page.title()).resolves.toMatch('Google');
});
});
@@ -0,0 +1,4 @@
import { Environment } from 'environment';
// eslint-disable-next-line
console.log(new Environment());
+13 -12
View File
@@ -54,9 +54,6 @@ const addClass = (elm, className) => {
classListAction(elm, className, (classList, clazz) => classList.add(clazz));
};
const hasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
const keys = (obj) => (obj ? Object.keys(obj) : []);
function each(source, callback) {
if (isArrayLike(source)) {
for (let i = 0; i < source.length; i++) {
@@ -65,7 +62,7 @@ function each(source, callback) {
}
}
} else if (source) {
each(keys(source), (key) => callback(source[key], key, source));
each(Object.keys(source), (key) => callback(source[key], key, source));
}
return source;
@@ -83,6 +80,7 @@ const from = (arr) => {
};
const contents = (elm) => (elm ? from(elm.childNodes) : []);
const parent = (elm) => (elm ? elm.parentElement : null);
const before = (parentElm, preferredAnchor, insertedElms) => {
if (insertedElms) {
@@ -123,10 +121,10 @@ const removeElements = (nodes) => {
if (isArrayLike(nodes)) {
each(from(nodes), (e) => removeElements(e));
} else if (nodes) {
const { parentNode } = nodes;
const parentElm = parent(nodes);
if (parentNode) {
parentNode.removeChild(nodes);
if (parentElm) {
parentElm.removeChild(nodes);
}
}
};
@@ -162,6 +160,9 @@ const clientSize = (elm) =>
: zeroObj;
const getBoundingClientRect = (elm) => elm.getBoundingClientRect();
const hasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
const keys = (obj) => (obj ? Object.keys(obj) : []);
const cssNumber = {
animationiterationcount: 1,
columncount: 1,
@@ -217,7 +218,7 @@ const zeroObj$1 = {
x: 0,
y: 0,
};
const offset = (elm) => {
const absoluteCoordinates = (elm) => {
const rect = elm ? getBoundingClientRect(elm) : 0;
return rect
? {
@@ -364,10 +365,10 @@ const rtlScrollBehavior = (parentElm, childElm) => {
overflowY: strHidden,
});
scrollLeft(parentElm, 0);
const parentOffset = offset(parentElm);
const childOffset = offset(childElm);
const parentOffset = absoluteCoordinates(parentElm);
const childOffset = absoluteCoordinates(childElm);
scrollLeft(parentElm, -999);
const childOffsetAfterScroll = offset(childElm);
const childOffsetAfterScroll = absoluteCoordinates(childElm);
return {
i: parentOffset.x === childOffset.x,
n: childOffset.x !== childOffsetAfterScroll.x,
@@ -436,7 +437,7 @@ class Environment {
removeAttr(envElm, 'style');
removeElements(envElm);
if (nativeScrollbarIsOverlaid.x && nativeScrollbarIsOverlaid.y) {
if (!nativeScrollbarIsOverlaid.x || !nativeScrollbarIsOverlaid.y) {
let size = windowSize();
let dpr = windowDPR();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+19 -16
View File
@@ -65,13 +65,6 @@
});
};
var hasOwnProperty = function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
};
var keys = function keys(obj) {
return obj ? Object.keys(obj) : [];
};
function each(source, callback) {
if (isArrayLike(source)) {
for (var i = 0; i < source.length; i++) {
@@ -80,7 +73,7 @@
}
}
} else if (source) {
each(keys(source), function (key) {
each(Object.keys(source), function (key) {
return callback(source[key], key, source);
});
}
@@ -102,6 +95,9 @@
var contents = function contents(elm) {
return elm ? from(elm.childNodes) : [];
};
var parent = function parent(elm) {
return elm ? elm.parentElement : null;
};
var before = function before(parentElm, preferredAnchor, insertedElms) {
if (insertedElms) {
@@ -144,10 +140,10 @@
return removeElements(e);
});
} else if (nodes) {
var parentNode = nodes.parentNode;
var parentElm = parent(nodes);
if (parentNode) {
parentNode.removeChild(nodes);
if (parentElm) {
parentElm.removeChild(nodes);
}
}
};
@@ -193,6 +189,13 @@
return elm.getBoundingClientRect();
};
var hasOwnProperty = function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
};
var keys = function keys(obj) {
return obj ? Object.keys(obj) : [];
};
var cssNumber = {
animationiterationcount: 1,
columncount: 1,
@@ -254,7 +257,7 @@
x: 0,
y: 0,
};
var offset = function offset(elm) {
var absoluteCoordinates = function absoluteCoordinates(elm) {
var rect = elm ? getBoundingClientRect(elm) : 0;
return rect
? {
@@ -405,10 +408,10 @@
overflowY: strHidden,
});
scrollLeft(parentElm, 0);
var parentOffset = offset(parentElm);
var childOffset = offset(childElm);
var parentOffset = absoluteCoordinates(parentElm);
var childOffset = absoluteCoordinates(childElm);
scrollLeft(parentElm, -999);
var childOffsetAfterScroll = offset(childElm);
var childOffsetAfterScroll = absoluteCoordinates(childElm);
return {
i: parentOffset.x === childOffset.x,
n: childOffset.x !== childOffsetAfterScroll.x,
@@ -478,7 +481,7 @@
removeAttr(envElm, 'style');
removeElements(envElm);
if (nativeScrollbarIsOverlaid.x && nativeScrollbarIsOverlaid.y) {
if (!nativeScrollbarIsOverlaid.x || !nativeScrollbarIsOverlaid.y) {
var size = windowSize();
var dpr = windowDPR();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -2
View File
@@ -3,8 +3,7 @@
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="Server Syncing API Code Challenge" />
<title>Server Syncing API</title>
<title>OverlayScrollbars</title>
</head>
<body>
@@ -1,4 +1,3 @@
import { keys } from 'support/utils/object';
import { isArrayLike } from 'support/utils/types';
import { PlainObject } from 'typings';
@@ -38,7 +37,7 @@ export function each<T>(
}
}
} else if (source) {
each(keys(source), (key) => callback(source[key], key, source));
each(Object.keys(source), (key) => callback(source[key], key, source));
}
return source;
}
@@ -1 +1,3 @@
import { Environment } from 'environment/environment';
export * from 'environment/environment';
export declare type OSEnvironment = Omit<Environment, 'addListener' | 'removeListener'>;
@@ -8,4 +8,4 @@ export declare const cssCache: {
};
export declare const cssProperty: (name: string) => string | undefined;
export declare const cssPropertyValue: (property: string, values: string, suffix?: string | undefined) => string | undefined;
export declare const jsAPI: (name: string) => any;
export declare const jsAPI: <T = any>(name: string) => T | undefined;
+2 -2
View File
@@ -1,3 +1,3 @@
import { XY } from 'support/dom';
export declare const offset: (elm: HTMLElement | null) => XY;
export declare const position: (elm: HTMLElement | null) => XY;
export declare const absoluteCoordinates: (elm: HTMLElement | null) => XY;
export declare const offsetCoordinates: (elm: HTMLElement | null) => XY;
@@ -1,5 +0,0 @@
export declare function extend<T, U>(target: T, object1: U): T & U;
export declare function extend<T, U, V>(target: T, object1: U, object2: V): T & U & V;
export declare function extend<T, U, V, W>(target: T, object1: U, object2: V, object3: W): T & U & V & W;
export declare function extend<T, U, V, W, X>(target: T, object1: U, object2: V, object3: W, object4: X): T & U & V & W & X;
export declare function extend<T, U, V, W, X, Y>(target: T, object1: U, object2: V, object3: W, object4: X, object5: Y): T & U & V & W & X & Y;
@@ -1,4 +1,3 @@
export * from 'support/utils/array';
export * from 'support/utils/object';
export * from 'support/utils/extend';
export * from 'support/utils/types';
@@ -1,2 +1,7 @@
export declare const hasOwnProperty: (obj: any, prop: string | number | symbol) => boolean;
export declare const keys: (obj: any) => Array<string>;
export declare function assignDeep<T, U>(target: T, object1: U): T & U;
export declare function assignDeep<T, U, V>(target: T, object1: U, object2: V): T & U & V;
export declare function assignDeep<T, U, V, W>(target: T, object1: U, object2: V, object3: W): T & U & V & W;
export declare function assignDeep<T, U, V, W, X>(target: T, object1: U, object2: V, object3: W, object4: X): T & U & V & W & X;
export declare function assignDeep<T, U, V, W, X, Y>(target: T, object1: U, object2: V, object3: W, object4: X, object5: Y): T & U & V & W & X & Y;
+2 -1
View File
@@ -1,4 +1,5 @@
{
"extensions": [".json", ".js", "jsx", ".ts", ".tsx", ".html"],
"directories": ["node_modules", "src"]
"directories": ["node_modules", "src"],
"projectRoot": "./packages"
}
+42 -30
View File
@@ -9,8 +9,19 @@ import fs from 'fs';
import path from 'path';
import resolve from './resolve.config.json';
const projectRootPath = './packages';
const buildConfigNames = ['build.config.js', 'build.config.json'];
const buildConfigDefaults = {
input: './src/index',
src: './src',
dist: './dist',
types: './types',
tests: './__tests__',
cache: [],
minVersions: true,
sourcemap: true,
esmBuild: true,
exports: 'auto',
};
const legacyBabelConfig = {
presets: [
@@ -41,51 +52,50 @@ const esmBabelConfig = {
],
};
const appendExtension = (file) => {
if (path.extname(file) === '') {
return file + resolve.extensions.find((ext) => fs.existsSync(path.resolve(`${file}${ext}`)));
}
return file;
};
const getBuildConfig = (projectPath) => {
const buildConfigName = buildConfigNames.find((name) => fs.existsSync(path.resolve(projectPath, name)));
return buildConfigName ? path.resolve(projectPath, buildConfigName) : '';
};
export default async (config, overwriteBuildConfig) => {
const resolvePath = (projectPath, rPath, appendExt) => {
const result = rPath ? (path.isAbsolute(rPath) ? rPath : path.resolve(projectPath, rPath)) : null;
return result && appendExt ? appendExtension(result) : result;
};
export default async (config, overwriteBuildConfig, silent) => {
const { 'config-project': project } = config;
const defaultInputName = './src/index';
const projectPath = path.resolve(__dirname, projectRootPath, project);
const projectPath = path.resolve(__dirname, resolve.projectRoot, project);
const packageJSONPath = path.resolve(projectPath, 'package.json');
const tsconfigJSONPath = path.resolve(projectPath, 'tsconfig.json');
const buildConfigPath = getBuildConfig(projectPath);
const isTypeScriptProject = fs.existsSync(tsconfigJSONPath);
const buildConfigDefaults = {
input: defaultInputName + resolve.extensions.find((ext) => fs.existsSync(path.resolve(projectPath, `${defaultInputName}${ext}`))),
src: './src',
dist: './dist',
types: './types',
tests: './tests',
cache: [],
minVersions: true,
sourcemap: true,
esmBuild: true,
name: project,
exports: 'auto',
};
const buildConfig = {
...buildConfigDefaults,
...{ name: project, file: project },
...(await import(buildConfigPath)),
...(overwriteBuildConfig || {}),
};
const { input, src, dist, types, tests, cache, minVersions, sourcemap, esmBuild, name, exports, globals } = buildConfig;
const { input, src, dist, types, tests, file, cache, minVersions, sourcemap, esmBuild, name, exports, globals } = buildConfig;
const { devDependencies = {}, peerDependencies = {} } = await import(packageJSONPath);
const srcPath = src ? path.resolve(projectPath, src) : null;
const distPath = dist ? path.resolve(projectPath, dist) : null;
const typesPath = types ? path.resolve(projectPath, types) : null;
const testsPath = tests ? path.resolve(projectPath, tests) : null;
const inputPath = input ? path.resolve(projectPath, input) : null;
const srcPath = resolvePath(projectPath, src);
const distPath = resolvePath(projectPath, dist);
const typesPath = resolvePath(projectPath, types);
const testsPath = resolvePath(projectPath, tests);
const inputPath = resolvePath(projectPath, input, true);
const genOutputConfig = (esm) => ({
format: esm ? 'esm' : 'umd',
file: path.resolve(distPath, `${project}${esm ? '.esm' : ''}.js`),
file: path.resolve(distPath, `${file}${esm ? '.esm' : ''}.js`),
sourcemap,
...(esm
? {}
@@ -157,10 +167,12 @@ export default async (config, overwriteBuildConfig) => {
};
};
console.log('');
console.log('PROJECT : ', project);
console.log('ENV : ', process.env.NODE_ENV);
console.log('CONFIG : ', buildConfig);
if (!silent) {
console.log('');
console.log('PROJECT : ', project);
console.log('ENV : ', process.env.NODE_ENV);
console.log('CONFIG : ', buildConfig);
}
const legacy = await genConfig({ esm: false, typeDeclaration: true });
const esm = esmBuild ? await genConfig({ esm: true, typeDeclaration: false }) : null;
@@ -176,7 +188,7 @@ export default async (config, overwriteBuildConfig) => {
name: 'deleteGeneratedDirs',
options() {
const deletedDirs = del.sync([distPath, typesPath].filter((curr) => curr !== null));
if (deletedDirs.length > 0) {
if (deletedDirs.length > 0 && !silent) {
console.log('Deleted directories:\n', deletedDirs.join('\n'));
}
},
@@ -188,7 +200,7 @@ export default async (config, overwriteBuildConfig) => {
writeBundle() {
const cacheDirs = cache.map((dir) => path.resolve(projectPath, dir));
const deletedDirs = del.sync(cacheDirs);
if (deletedDirs.length > 0) {
if (deletedDirs.length > 0 && !silent) {
console.log('Deleted cache:\n', deletedDirs.join('\n'));
}
},