diff --git a/biome.json b/biome.json index dd8691beddd..9f6e2acb25c 100644 --- a/biome.json +++ b/biome.json @@ -4,6 +4,7 @@ "files": { "maxSize": 10000000, "includes": [ + "**/esbuild-config.js", "**/src/**", "**/lib/**", "**/test/**", diff --git a/devtools/dashboard_utilities.mjs b/devtools/dashboard_utilities.mjs new file mode 100644 index 00000000000..8ff5c109e61 --- /dev/null +++ b/devtools/dashboard_utilities.mjs @@ -0,0 +1,67 @@ +import fs from 'fs'; +import path from 'path'; +import constants from '../tasks/util/constants.js'; + +function readFilePromise(file) { + return new Promise((resolve, reject) => { + fs.readFile(file, { encoding: 'utf-8' }, (err, contents) => { + if (err) reject(err); + else resolve({ name: file, contents: contents }); + }); + }); +} + +function writeFilePromise(path, contents) { + return new Promise((resolve, reject) => { + fs.writeFile(path, contents, (err) => { + if (err) reject(err); + else resolve(path); + }); + }); +} + +export function getMockFiles() { + return new Promise((resolve, reject) => { + fs.readdir(constants.pathToTestImageMocks, (err, files) => { + if (err) reject(err); + else resolve(files); + }); + }); +} + +export function readFiles(files) { + const promises = files.map((file) => readFilePromise(path.join(constants.pathToTestImageMocks, file))); + + return Promise.all(promises); +} + +export function createMocksList(files) { + // eliminate pollutants (e.g .DS_Store) that can accumulate in the mock directory + const jsonFiles = files.filter((file) => file.name.substr(-5) === '.json'); + + const mocksList = jsonFiles.map((file) => { + const contents = JSON.parse(file.contents); + + // get plot type keywords from mocks + const types = contents.data + .map((trace) => trace.type || 'scatter') + .reduce((acc, type, i, arr) => (arr.lastIndexOf(type) === i ? [...acc, type] : acc), []); + + const filename = file.name.split(path.sep).pop(); + + return { + name: filename.slice(0, -5), + file: filename, + keywords: types.join(', ') + }; + }); + + return mocksList; +} + +function saveListToFile(filePath, fileName) { + return (list) => writeFilePromise(path.join(filePath, fileName), JSON.stringify(list, null, 2)); +} + +export const saveMockListToFile = saveListToFile(constants.pathToBuild, 'test_dashboard_mocks.json'); +export const saveReglTracesToFile = saveListToFile(constants.pathToBuild, 'regl_traces.json'); diff --git a/devtools/regl_codegen/server.mjs b/devtools/regl_codegen/server.mjs index 265c6572e3c..7cd15d8486f 100644 --- a/devtools/regl_codegen/server.mjs +++ b/devtools/regl_codegen/server.mjs @@ -1,26 +1,25 @@ +import ecstatic from 'ecstatic'; +import { build } from 'esbuild'; import fs from 'fs'; -import path from 'path'; import http from 'http'; -import ecstatic from 'ecstatic'; -import open from 'open'; import minimist from 'minimist'; - +import open from 'open'; +import path from 'path'; +import { localDevReglCodegenConfig as config } from '../../esbuild-config.js'; import constants from '../../tasks/util/constants.js'; -import { build } from 'esbuild'; -import config from '../../esbuild-config.js'; +import { + createMocksList, + getMockFiles, + readFiles, + saveMockListToFile, + saveReglTracesToFile +} from '../dashboard_utilities.mjs'; var args = minimist(process.argv.slice(2), {}); var PORT = args.port || 3000; var strict = args.strict; -var reglTraceList = [ - 'parcoords', - 'scattergl', - 'scatterpolargl', - 'splom' -]; - - +var reglTraceList = ['parcoords', 'scattergl', 'scatterpolargl', 'splom']; // Create server var _static = ecstatic({ @@ -32,13 +31,13 @@ var _static = ecstatic({ var tracesReceived = []; -var server = http.createServer(function(req, res) { - if(req.method === 'POST' && req.url === '/api/submit-code') { +var server = http.createServer(function (req, res) { + if (req.method === 'POST' && req.url === '/api/submit-code') { var body = ''; - req.on('data', function(data) { + req.on('data', function (data) { body += data; }); - req.on('end', function() { + req.on('end', function () { var data = JSON.parse(body); tracesReceived.push(data.trace); @@ -46,7 +45,7 @@ var server = http.createServer(function(req, res) { res.statusCode = 200; res.end(); }); - } else if(req.method === 'GET' && req.url === '/api/codegen-done') { + } else if (req.method === 'GET' && req.url === '/api/codegen-done') { console.log('Codegen complete'); console.log('Traces received:', tracesReceived); @@ -71,106 +70,8 @@ server.listen(PORT); // open up browser window open('http://localhost:' + PORT + '/devtools/regl_codegen/index' + (strict ? '-strict' : '') + '.html'); -var devtoolsPath = path.join(constants.pathToRoot, 'devtools/regl_codegen'); -config.entryPoints = [path.join(devtoolsPath, 'devtools.js')]; -config.outfile = './build/regl_codegen-bundle.js'; -config.sourcemap = false; -config.minify = false; await build(config); -function getMockFiles() { - return new Promise(function(resolve, reject) { - fs.readdir(constants.pathToTestImageMocks, function(err, files) { - if(err) { - reject(err); - } else { - resolve(files); - } - }); - }); -} - -function readFiles(files) { - var promises = files.map(function(file) { - var filePath = path.join(constants.pathToTestImageMocks, file); - return readFilePromise(filePath); - }); - - return Promise.all(promises); -} - -function createMocksList(files) { - // eliminate pollutants (e.g .DS_Store) that can accumulate in the mock directory - var jsonFiles = files.filter(function(file) { - return file.name.substr(-5) === '.json'; - }); - - var mocksList = jsonFiles.map(function(file) { - var contents = JSON.parse(file.contents); - - // get plot type keywords from mocks - var types = contents.data.map(function(trace) { - return trace.type || 'scatter'; - }).reduce(function(acc, type, i, arr) { - if(arr.lastIndexOf(type) === i) { - acc.push(type); - } - return acc; - }, []); - - var filename = file.name.split(path.sep).pop(); - - return { - name: filename.slice(0, -5), - file: filename, - keywords: types.join(', ') - }; - }); - - return mocksList; -} - -function saveMockListToFile(mocksList) { - var filePath = path.join(constants.pathToBuild, 'test_dashboard_mocks.json'); - var content = JSON.stringify(mocksList, null, 4); - - return writeFilePromise(filePath, content); -} - -function saveReglTracesToFile(traces) { - var filePath = path.join(constants.pathToBuild, 'regl_traces.json'); - var content = JSON.stringify(traces, null, 4); - - return writeFilePromise(filePath, content); -} - -function readFilePromise(file) { - return new Promise(function(resolve, reject) { - fs.readFile(file, { encoding: 'utf-8' }, function(err, contents) { - if(err) { - reject(err); - } else { - resolve({ - name: file, - contents: contents - }); - } - }); - }); -} - -function writeFilePromise(path, contents) { - return new Promise(function(resolve, reject) { - fs.writeFile(path, contents, function(err) { - if(err) { - reject(err); - } else { - resolve(path); - } - }); - }); -} - function handleCodegen(data) { var trace = data.trace; var generated = data.generated; @@ -178,31 +79,23 @@ function handleCodegen(data) { var pathToReglCodegenSrc = constants.pathToReglCodegenSrc; var pathToReglPrecompiledSrc = path.join(constants.pathToSrc, 'traces', trace, 'regl_precompiled.js'); - var header = [ - '\'use strict\';', - '', - ].join('\n'); + var header = ["'use strict';", ''].join('\n'); var imports = ''; - var exports = [ - '', - '/* eslint-disable quote-props */', - 'module.exports = {', - '', - ].join('\n'); + var exports = ['', '/* eslint-disable quote-props */', 'module.exports = {', ''].join('\n'); var varId = 0; - Object.entries(generated).forEach(function(kv) { + Object.entries(generated).forEach(function (kv) { var key = kv[0]; var value = kv[1]; var filePath = path.join(pathToReglCodegenSrc, key); fs.writeFileSync(filePath, 'module.exports = ' + value); - imports += 'var v' + varId + ' = require(\'../../' + path.join(constants.reglCodegenSubdir, key) + '\');\n'; - exports += ' \'' + key + '\': v' + varId + ',\n'; + imports += 'var v' + varId + " = require('../../" + path.join(constants.reglCodegenSubdir, key) + "');\n"; + exports += " '" + key + "': v" + varId + ',\n'; varId++; }); - if(varId > 0) { + if (varId > 0) { exports = exports.slice(0, -2) + '\n};\n'; } else { exports = 'module.exports = {};\n'; diff --git a/devtools/test_dashboard/server.mjs b/devtools/test_dashboard/server.mjs index b0adbd7ece4..f1c7ca071ed 100644 --- a/devtools/test_dashboard/server.mjs +++ b/devtools/test_dashboard/server.mjs @@ -1,15 +1,11 @@ -import fs from 'fs'; -import path from 'path'; -import http from 'http'; import ecstatic from 'ecstatic'; -import open from 'open'; +import { build, context } from 'esbuild'; +import http from 'http'; import minimist from 'minimist'; - +import open from 'open'; +import { devtoolsConfig, localDevConfig } from '../../esbuild-config.js'; import constants from '../../tasks/util/constants.js'; -import { context, build } from 'esbuild'; -import config from '../../esbuild-config.js'; - -import { glsl } from 'esbuild-plugin-glsl'; +import { createMocksList, getMockFiles, readFiles, saveMockListToFile } from '../dashboard_utilities.mjs'; var args = minimist(process.argv.slice(2), {}); var PORT = args.port || 3000; @@ -17,46 +13,14 @@ var strict = args.strict; var mathjax3 = args.mathjax3; var mathjax3chtml = args.mathjax3chtml; -if(strict) { - config.entryPoints = ['./lib/index-strict.js']; -} - -config.outfile = './build/plotly.js'; - -var mockFolder = constants.pathToTestImageMocks; +if (strict) localDevConfig.entryPoints = ['./lib/index-strict.js']; // mock list -await getMockFiles() - .then(readFiles) - .then(createMocksList) - .then(saveMockListToFile); - -// Devtools config -var devtoolsConfig = { - entryPoints: [ - path.join(constants.pathToRoot, 'devtools', 'test_dashboard', 'devtools.js') - ], - outfile: path.join(constants.pathToRoot, 'build', 'test_dashboard-bundle.js'), - format: 'cjs', - globalName: 'Tabs', - bundle: true, - minify: false, - sourcemap: false, - plugins: [ - glsl({ - minify: true, - }), - ], - define: { - global: 'window', - }, - target: 'es2016', - logLevel: 'info', -}; +await getMockFiles().then(readFiles).then(createMocksList).then(saveMockListToFile); build(devtoolsConfig); -var ctx = await context(config); +var ctx = await context(localDevConfig); devServer(); console.log('watching esbuild...'); await ctx.watch(); @@ -70,7 +34,7 @@ function devServer() { }); const server = http.createServer((req, res) => { - if(strict) { + if (strict) { res.setHeader( 'Content-Security-Policy', // Comment/uncomment for testing CSP. Changes require a server restart. @@ -83,108 +47,22 @@ function devServer() { // "connect-src 'self'", // "object-src 'none'", // "base-uri 'self';", - "worker-src blob:", - ].join("; ") - ) + 'worker-src blob:' + ].join('; ') + ); } - staticFilesHandler(req, res) - }) + staticFilesHandler(req, res); + }); // Start the server up! server.listen(PORT); let indexName = 'index'; - if(mathjax3) indexName += '-mathjax3' - else if(mathjax3chtml) indexName += '-mathjax3chtml' - indexName += '.html' + if (mathjax3) indexName += '-mathjax3'; + else if (mathjax3chtml) indexName += '-mathjax3chtml'; + indexName += '.html'; // open up browser window open(`http://localhost:${PORT}/devtools/test_dashboard/${indexName}${strict ? '?strict=true' : ''}`); } - -function getMockFiles() { - return new Promise(function(resolve, reject) { - fs.readdir(mockFolder, function(err, files) { - if(err) { - reject(err); - } else { - resolve(files); - } - }); - }); -} - -function readFiles(files) { - var promises = files.map(function(file) { - var filePath = path.join(mockFolder, file); - return readFilePromise(filePath); - }); - - return Promise.all(promises); -} - -function createMocksList(files) { - // eliminate pollutants (e.g .DS_Store) that can accumulate in the mock directory - var jsonFiles = files.filter(function(file) { - return file.name.substr(-5) === '.json'; - }); - - var mocksList = jsonFiles.map(function(file) { - var contents = JSON.parse(file.contents); - - // get plot type keywords from mocks - var types = contents.data.map(function(trace) { - return trace.type || 'scatter'; - }).reduce(function(acc, type, i, arr) { - if(arr.lastIndexOf(type) === i) { - acc.push(type); - } - return acc; - }, []); - - var filename = file.name.split(path.sep).pop(); - - return { - name: filename.slice(0, -5), - file: filename, - keywords: types.join(', ') - }; - }); - - return mocksList; -} - -function saveMockListToFile(mocksList) { - var filePath = path.join(constants.pathToBuild, 'test_dashboard_mocks.json'); - var content = JSON.stringify(mocksList, null, 4); - - return writeFilePromise(filePath, content); -} - -function readFilePromise(file) { - return new Promise(function(resolve, reject) { - fs.readFile(file, { encoding: 'utf-8' }, function(err, contents) { - if(err) { - reject(err); - } else { - resolve({ - name: file, - contents: contents - }); - } - }); - }); -} - -function writeFilePromise(path, contents) { - return new Promise(function(resolve, reject) { - fs.writeFile(path, contents, function(err) { - if(err) { - reject(err); - } else { - resolve(path); - } - }); - }); -} diff --git a/esbuild-config.js b/esbuild-config.js index 3f37992ec0a..77c6931cd48 100644 --- a/esbuild-config.js +++ b/esbuild-config.js @@ -1,30 +1,62 @@ -var glsl = require('esbuild-plugin-glsl').glsl; -var environmentPlugin = require('esbuild-plugin-environment').environmentPlugin; +const { environmentPlugin } = require('esbuild-plugin-environment'); +const { glsl } = require('esbuild-plugin-glsl'); const InlineCSSPlugin = require('esbuild-plugin-inline-css'); +const path = require('path'); +const constants = require('./tasks/util/constants.js'); -module.exports = { +// Default config used when building library +const esbuildConfig = { entryPoints: ['./lib/index.js'], format: 'iife', globalName: 'Plotly', bundle: true, minify: false, sourcemap: false, - plugins: [ - InlineCSSPlugin(), - glsl({ - minify: true, - }), - environmentPlugin({ - NODE_DEBUG: false, - }), - ], + plugins: [InlineCSSPlugin(), glsl({ minify: true }), environmentPlugin({ NODE_DEBUG: false })], alias: { - stream: 'stream-browserify', + stream: 'stream-browserify' }, define: { global: 'window', - 'define.amd': 'false', + 'define.amd': 'false' }, target: 'es2016', - logLevel: 'info', + logLevel: 'info' +}; + +// Config used when building bundle to serve test dashboard +const devtoolsConfig = { + entryPoints: [path.join(constants.pathToRoot, 'devtools', 'test_dashboard', 'devtools.js')], + outfile: path.join(constants.pathToRoot, 'build', 'test_dashboard-bundle.js'), + format: 'cjs', + globalName: 'Tabs', + bundle: true, + minify: false, + sourcemap: false, + plugins: [glsl({ minify: true })], + define: { global: 'window' }, + target: 'es2016', + logLevel: 'info' +}; + +// Config used when building plotly.js for local development +const localDevConfig = { + ...esbuildConfig, + outfile: './build/plotly.js' +}; + +// Config used when building bundle to serve regl +const localDevReglCodegenConfig = { + ...esbuildConfig, + entryPoints: [path.join(constants.pathToRoot, 'devtools/regl_codegen', 'devtools.js')], + outfile: './build/regl_codegen-bundle.js', + sourcemap: false, + minify: false +}; + +module.exports = { + devtoolsConfig, + esbuildConfig, + localDevConfig, + localDevReglCodegenConfig }; diff --git a/package.json b/package.json index 32ca49508b7..d41047ca1cb 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "webpack": "./dist/plotly.js", "repository": { "type": "git", - "url": "https://github.com/plotly/plotly.js.git" + "url": "git+https://github.com/plotly/plotly.js.git" }, "bugs": { "url": "https://github.com/plotly/plotly.js/issues" diff --git a/tasks/schema.mjs b/tasks/schema.mjs index 2c332afbe48..b4a335f99dc 100644 --- a/tasks/schema.mjs +++ b/tasks/schema.mjs @@ -1,36 +1,24 @@ +import { build } from 'esbuild'; import fs from 'fs'; import path from 'path'; +import { localDevConfig } from '../esbuild-config.js'; import constants from './util/constants.js'; import plotlyNode from './util/plotly_node.mjs'; -function caseInsensitive(a, b) { - return a.toLowerCase().localeCompare(b.toLowerCase()); -} +const caseInsensitive = (a, b) => a.toLowerCase().localeCompare(b.toLowerCase()); -function isArray(v) { - return Array.isArray(v); -} +const { isArray } = Array; -function isObject(v) { - return typeof v === 'object' && v !== null && !(isArray(v)); -} +const isObject = (v) => typeof v === 'object' && v !== null && !isArray(v); -function isArrayOfObjects(v) { - return isArray(v) && isObject(v[0]); -} +const isArrayOfObjects = (v) => isArray(v) && isObject(v[0]); -function typeHandle(v) { - return ( - isArrayOfObjects(v) ? sortArrayOfObjects(v) : - isObject(v) ? sortObject(v) : - v - ); -} +const typeHandle = (v) => (isArrayOfObjects(v) ? sortArrayOfObjects(v) : isObject(v) ? sortObject(v) : v); function sortArrayOfObjects(list) { - var newList = []; - for(var i = 0; i < list.length; i++) { + const newList = []; + for (let i = 0; i < list.length; i++) { newList[i] = typeHandle(list[i]); } @@ -38,12 +26,12 @@ function sortArrayOfObjects(list) { } function sortObject(obj) { - var allKeys = Object.keys(obj); + const allKeys = Object.keys(obj); allKeys.sort(caseInsensitive); - var newObj = {}; - for(var i = 0; i < allKeys.length; i++) { - var key = allKeys[i]; + const newObj = {}; + for (let i = 0; i < allKeys.length; i++) { + const key = allKeys[i]; newObj[key] = typeHandle(obj[key]); } @@ -51,35 +39,34 @@ function sortObject(obj) { } function makeSchema(plotlyPath, schemaPath) { - var Plotly = plotlyNode(plotlyPath); - - var obj = Plotly.PlotSchema.get(); - var sortedObj = sortObject(obj); - var plotSchemaRaw = JSON.stringify(obj, null, 1); - var plotSchemaStr = JSON.stringify(sortedObj, null, 1); + const Plotly = plotlyNode(plotlyPath); + const obj = Plotly.PlotSchema.get(); + const sortedObj = sortObject(obj); + const plotSchemaRaw = JSON.stringify(obj, null, 1); + const plotSchemaStr = JSON.stringify(sortedObj, null, 1); fs.writeFileSync(schemaPath, plotSchemaStr); - var lenBeforeSort = plotSchemaRaw.length; - var lenAfterSort = plotSchemaStr.length; - var linesBeforeSort = plotSchemaRaw.split('\n').length; - var linesAfterSort = plotSchemaStr.split('\n').length; - if(linesAfterSort !== linesBeforeSort || lenAfterSort !== lenBeforeSort) { + const lenBeforeSort = plotSchemaRaw.length; + const lenAfterSort = plotSchemaStr.length; + const linesBeforeSort = plotSchemaRaw.split('\n').length; + const linesAfterSort = plotSchemaStr.split('\n').length; + if (linesAfterSort !== linesBeforeSort || lenAfterSort !== lenBeforeSort) { throw 'plot schema should have the same length & number of lines before and after sort'; } else { console.log('ok ' + path.basename(schemaPath)); } } -var isDist = process.argv.indexOf('dist') !== -1; +const isDist = process.argv.indexOf('dist') !== -1; + +const pathToSchema = isDist ? constants.pathToSchemaDist : constants.pathToSchemaDiff; -var pathToSchema = isDist ? - constants.pathToSchemaDist : - constants.pathToSchemaDiff; +const pathToPlotly = isDist ? constants.pathToPlotlyDistWithMeta : constants.pathToPlotlyBuild; -var pathToPlotly = isDist ? - constants.pathToPlotlyDistWithMeta : - constants.pathToPlotlyBuild; +// Build plotly.js to ensure changes to attributes are picked up. This is the same +// process used in the test dashboard server script, but run only once. +await build(localDevConfig); // output plot-schema JSON makeSchema(pathToPlotly, pathToSchema); diff --git a/tasks/util/bundle_wrapper.mjs b/tasks/util/bundle_wrapper.mjs index 561588a58f5..a4cb0d43e62 100644 --- a/tasks/util/bundle_wrapper.mjs +++ b/tasks/util/bundle_wrapper.mjs @@ -4,7 +4,7 @@ import prependFile from 'prepend-file'; import { build } from 'esbuild'; -import esbuildConfig from '../../esbuild-config.js'; +import { esbuildConfig } from '../../esbuild-config.js'; import esbuildPluginStripMeta from '../../tasks/compress_attributes.js'; import common from './common.js'; @@ -35,17 +35,17 @@ export default async function _bundle(pathToIndex, pathToBundle, opts, cb) { config.outfile = pathToBundle; config.minify = !!opts.minify; - if(!opts.noCompressAttributes) { + if (!opts.noCompressAttributes) { config.plugins = basePlugins.concat([esbuildPluginStripMeta]); } - if(opts.noPlugins) config.plugins = []; + if (opts.noPlugins) config.plugins = []; await build(config); addWrapper(pathToBundle); - if(cb) cb(); + if (cb) cb(); } // Until https://github.com/evanw/esbuild/pull/513 is merged @@ -67,14 +67,5 @@ function addWrapper(path) { common.throwOnError ); - fsExtra.appendFile( - path, - [ - '', - 'window.Plotly = Plotly;', - 'return Plotly;', - '}));', - ].join('\n'), - common.throwOnError - ); + fsExtra.appendFile(path, ['', 'window.Plotly = Plotly;', 'return Plotly;', '}));'].join('\n'), common.throwOnError); } diff --git a/test/jasmine/karma.conf.js b/test/jasmine/karma.conf.js index b1f52a8306d..c82cc9bfba6 100644 --- a/test/jasmine/karma.conf.js +++ b/test/jasmine/karma.conf.js @@ -3,7 +3,7 @@ var path = require('path'); var minimist = require('minimist'); var constants = require('../../tasks/util/constants'); -var esbuildConfig = require('../../esbuild-config.js'); +const { esbuildConfig } = require('../../esbuild-config.js'); var isCI = Boolean(process.env.CI); @@ -12,17 +12,24 @@ var argv = minimist(process.argv.slice(4), { boolean: [ 'mathjax3', 'info', - 'nowatch', 'randomize', - 'failFast', 'doNotFailOnEmptyTestSuite', - 'Chrome', 'Firefox', - 'verbose', 'showSkipped', 'report-progress', 'report-spec', 'report-dots' + 'nowatch', + 'randomize', + 'failFast', + 'doNotFailOnEmptyTestSuite', + 'Chrome', + 'Firefox', + 'verbose', + 'showSkipped', + 'report-progress', + 'report-spec', + 'report-dots' ], alias: { Chrome: 'chrome', Firefox: ['firefox', 'FF'], bundleTest: ['bundletest', 'bundle_test'], nowatch: 'no-watch', - failFast: 'fail-fast', + failFast: 'fail-fast' }, default: { info: false, @@ -37,78 +44,80 @@ var argv = minimist(process.argv.slice(4), { } }); -if(argv.info) { - console.log([ - 'plotly.js karma runner for jasmine tests CLI info', - '', - 'Examples:', - '', - 'Run `axes_test.js`, `bar_test.js` and `scatter_test.js` suites w/o `autoWatch`:', - ' $ npm run test-jasmine -- axes bar_test.js scatter --nowatch', - '', - 'Run all tests with the `noCI` tag on Firefox in a 1500px wide window:', - ' $ npm run test-jasmine -- --tags=noCI --FF --width=1500', - '', - 'Arguments:', - ' - All non-flagged arguments corresponds to the test suites in `test/jasmine/tests/` to be run.', - ' No need to add the `_test.js` suffix, we expand them correctly here.', - ' - `--bundleTest` set the bundle test suite `test/jasmine/bundle_tests/ to be run.', - ' Note that only one bundle test can be run at a time.', - ' - Use `--tags` to specify which `@` tags to test (if any) e.g `npm run test-jasmine -- --tags=gl`', - ' will run only gl tests.', - ' - Use `--skip-tags` to specify which `@` tags to skip (if any) e.g `npm run test-jasmine -- --skip-tags=gl`', - ' will skip all gl tests.', - '', - 'Other options:', - ' - `--info`: show this info message', - ' - `--mathjax3`: to load mathjax v3 in relevant test', - ' - `--Chrome` (alias `--chrome`): run test in (our custom) Chrome browser', - ' - `--Firefox` (alias `--FF`, `--firefox`): run test in (our custom) Firefox browser', - ' - `--nowatch (dflt: `false`, `true` on CI)`: run karma w/o `autoWatch` / multiple run mode', - ' - `--randomize` (dflt: `false`): randomize test ordering (useful to detect bad test teardown)', - ' - `--failFast` (dflt: `false`): exit karma upon first test failure', - ' - `--doNotFailOnEmptyTestSuite` (dflt: `false`): do not fail run when no spec are ran (either from bundle error OR tag filtering)', - ' - `--tags`: run only test with given tags (using the `jasmine-spec-tags` framework)', - ' - `--width`(dflt: 1035): set width of the browser window', - ' - `--height` (dflt: 617): set height of the browser window', - ' - `--verbose` (dflt: `false`): show test result using verbose reporter', - ' - `--showSkipped` show tests that are skipped', - ' - `--report-progress`: use *progress* reporter', - ' - `--report-spec`: use *spec* reporter', - ' - `--report-dots`: use *dots* reporter', - '', - 'For info on the karma CLI options run `npm run test-jasmine -- --help`' - ].join('\n')); +if (argv.info) { + console.log( + [ + 'plotly.js karma runner for jasmine tests CLI info', + '', + 'Examples:', + '', + 'Run `axes_test.js`, `bar_test.js` and `scatter_test.js` suites w/o `autoWatch`:', + ' $ npm run test-jasmine -- axes bar_test.js scatter --nowatch', + '', + 'Run all tests with the `noCI` tag on Firefox in a 1500px wide window:', + ' $ npm run test-jasmine -- --tags=noCI --FF --width=1500', + '', + 'Arguments:', + ' - All non-flagged arguments corresponds to the test suites in `test/jasmine/tests/` to be run.', + ' No need to add the `_test.js` suffix, we expand them correctly here.', + ' - `--bundleTest` set the bundle test suite `test/jasmine/bundle_tests/ to be run.', + ' Note that only one bundle test can be run at a time.', + ' - Use `--tags` to specify which `@` tags to test (if any) e.g `npm run test-jasmine -- --tags=gl`', + ' will run only gl tests.', + ' - Use `--skip-tags` to specify which `@` tags to skip (if any) e.g `npm run test-jasmine -- --skip-tags=gl`', + ' will skip all gl tests.', + '', + 'Other options:', + ' - `--info`: show this info message', + ' - `--mathjax3`: to load mathjax v3 in relevant test', + ' - `--Chrome` (alias `--chrome`): run test in (our custom) Chrome browser', + ' - `--Firefox` (alias `--FF`, `--firefox`): run test in (our custom) Firefox browser', + ' - `--nowatch (dflt: `false`, `true` on CI)`: run karma w/o `autoWatch` / multiple run mode', + ' - `--randomize` (dflt: `false`): randomize test ordering (useful to detect bad test teardown)', + ' - `--failFast` (dflt: `false`): exit karma upon first test failure', + ' - `--doNotFailOnEmptyTestSuite` (dflt: `false`): do not fail run when no spec are ran (either from bundle error OR tag filtering)', + ' - `--tags`: run only test with given tags (using the `jasmine-spec-tags` framework)', + ' - `--width`(dflt: 1035): set width of the browser window', + ' - `--height` (dflt: 617): set height of the browser window', + ' - `--verbose` (dflt: `false`): show test result using verbose reporter', + ' - `--showSkipped` show tests that are skipped', + ' - `--report-progress`: use *progress* reporter', + ' - `--report-spec`: use *spec* reporter', + ' - `--report-dots`: use *dots* reporter', + '', + 'For info on the karma CLI options run `npm run test-jasmine -- --help`' + ].join('\n') + ); process.exit(0); } var SUFFIX = '_test.js'; -var basename = function(s) { return path.basename(s, SUFFIX); }; -var merge = function(_) { +var basename = function (s) { + return path.basename(s, SUFFIX); +}; +var merge = function (_) { var list = []; - (Array.isArray(_) ? _ : [_]).forEach(function(p) { + (Array.isArray(_) ? _ : [_]).forEach(function (p) { list = list.concat(p.split(',')); }); return list; }; -var glob = function(_) { - return _.length === 1 ? - _[0] + SUFFIX : - '{' + _.join(',') + '}' + SUFFIX; +var glob = function (_) { + return _.length === 1 ? _[0] + SUFFIX : '{' + _.join(',') + '}' + SUFFIX; }; var isBundleTest = !!argv.bundleTest; var isFullSuite = !isBundleTest && argv._.length === 0; var testFileGlob; -if(isFullSuite) { +if (isFullSuite) { testFileGlob = path.join(__dirname, 'tests', '*' + SUFFIX); -} else if(isBundleTest) { +} else if (isBundleTest) { var _ = merge(argv.bundleTest); - if(_.length > 1) { + if (_.length > 1) { console.warn('Can only run one bundle test suite at a time, ignoring ', _.slice(1)); } @@ -124,15 +133,15 @@ var pathToMathJax3 = path.join(__dirname, '..', '..', 'node_modules', '@plotly/m var pathToVirtualWebgl = path.join(__dirname, '..', '..', 'node_modules', 'virtual-webgl', 'src', 'virtual-webgl.js'); var reporters = []; -if(argv['report-progress'] || argv['report-spec'] || argv['report-dots']) { - if(argv['report-progress']) reporters.push('progress'); - if(argv['report-spec']) reporters.push('spec'); - if(argv['report-dots']) reporters.push('dots'); +if (argv['report-progress'] || argv['report-spec'] || argv['report-dots']) { + if (argv['report-progress']) reporters.push('progress'); + if (argv['report-spec']) reporters.push('spec'); + if (argv['report-dots']) reporters.push('dots'); } else { - if(isCI) { + if (isCI) { reporters.push('spec'); } else { - if(isFullSuite) { + if (isFullSuite) { reporters.push('dots'); } else { reporters.push('progress'); @@ -142,10 +151,10 @@ if(argv['report-progress'] || argv['report-spec'] || argv['report-dots']) { var hasSpecReporter = reporters.indexOf('spec') !== -1; -if(!hasSpecReporter && argv.showSkipped) reporters.push('spec'); -if(argv.verbose) reporters.push('verbose'); +if (!hasSpecReporter && argv.showSkipped) reporters.push('spec'); +if (argv.verbose) reporters.push('verbose'); -if(process.argv.indexOf('--tags=noCI,noCIdep') !== -1) { +if (process.argv.indexOf('--tags=noCI,noCIdep') !== -1) { reporters = ['dots']; } @@ -169,7 +178,6 @@ function func(config) { } func.defaultConfig = { - // base path that will be used to resolve all patterns (eg. files, exclude) basePath: constants.pathToRoot, @@ -184,7 +192,7 @@ func.defaultConfig = { require('karma-spec-reporter'), require('karma-chrome-launcher'), require('karma-firefox-launcher'), - require('karma-esbuild'), + require('karma-esbuild') ], // list of files / patterns to load in the browser @@ -194,9 +202,9 @@ func.defaultConfig = { pathToCustomMatchers, // available to fetch from /base/node_modules/@plotly/mathjax-v2/ // more info: http://karma-runner.github.io/3.0/config/files.html - {pattern: pathToMathJax2 + '/**', included: false, watched: false, served: true}, - {pattern: pathToMathJax3 + '/**', included: false, watched: false, served: true}, - {pattern: pathToTopojsonDist + '/**', included: false, watched: false, served: true} + { pattern: pathToMathJax2 + '/**', included: false, watched: false, served: true }, + { pattern: pathToMathJax3 + '/**', included: false, watched: false, served: true }, + { pattern: pathToTopojsonDist + '/**', included: false, watched: false, served: true } ], // list of files / pattern to exclude @@ -253,7 +261,7 @@ func.defaultConfig = { '--touch-events', '--window-size=' + argv.width + ',' + argv.height, isCI ? '--ignore-gpu-blacklist' : '', - (isBundleTest && basename(testFileGlob) === 'no_webgl') ? '--disable-webgl' : '' + isBundleTest && basename(testFileGlob) === 'no_webgl' ? '--disable-webgl' : '' ] }, _Firefox: { @@ -318,11 +326,9 @@ func.defaultConfig = { func.defaultConfig.preprocessors[pathToCustomMatchers] = ['esbuild']; func.defaultConfig.preprocessors[testFileGlob] = ['esbuild']; -if(argv.virtualWebgl) { +if (argv.virtualWebgl) { // add virtual-webgl to the top - func.defaultConfig.files = [ - pathToVirtualWebgl - ].concat(func.defaultConfig.files); + func.defaultConfig.files = [pathToVirtualWebgl].concat(func.defaultConfig.files); } // lastly, load test file glob @@ -330,8 +336,8 @@ func.defaultConfig.files.push(testFileGlob); // add browsers var browsers = func.defaultConfig.browsers; -if(argv.Chrome) browsers.push('_Chrome'); -if(argv.Firefox) browsers.push('_Firefox'); -if(browsers.length === 0) browsers.push('_Chrome'); +if (argv.Chrome) browsers.push('_Chrome'); +if (argv.Firefox) browsers.push('_Firefox'); +if (browsers.length === 0) browsers.push('_Chrome'); module.exports = func;