From 3f731c85ac75b6cc8cfca935caa2c64389c383c0 Mon Sep 17 00:00:00 2001 From: Alex Potsides Date: Wed, 6 Apr 2022 12:32:49 +0100 Subject: [PATCH] feat: support ESM config files (#414) Uses `import` for dynamic module imports allowing you to use ESM as a config file. Also lets you return a function that returns a promise to get the config in case you need to do some async work to retrieve it from somewhere. Fixes #413 --- .gitignore | 1 + cli.js | 39 +++++++++++++++++++++++++++------ mocks/sw/sw.config.mjs | 10 +++++++++ mocks/sw/sw.function.config.mjs | 12 ++++++++++ mocks/sw/sw.promise.config.mjs | 10 +++++++++ test.js | 36 ++++++++++++++++++++++++++++++ 6 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 mocks/sw/sw.config.mjs create mode 100644 mocks/sw/sw.function.config.mjs create mode 100644 mocks/sw/sw.promise.config.mjs diff --git a/.gitignore b/.gitignore index fd6c9338..071b5bd7 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ node_modules coverage.lcov yarn-error.log dist +.tmp diff --git a/cli.js b/cli.js index 970fc26d..ea825d22 100755 --- a/cli.js +++ b/cli.js @@ -5,7 +5,7 @@ import path from 'path' import sade from 'sade' import kleur from 'kleur' import { fileURLToPath } from 'url' -import { lilconfigSync } from 'lilconfig' +import { lilconfig } from 'lilconfig' import mergeOptions from 'merge-options' import { runnerOptions } from './src/utils/index.js' import UvuRunner from './src/runner-uvu.js' @@ -105,6 +105,22 @@ const sade2 = new Proxy(sade('playwright-test [files]', true), { }, }) +const loadEsm = async (/** @type {string} */ filepath) => { + /** @type {any} */ + const res = await import(filepath) + + if (res.default) { + return res.default + } + + return res +} + +const configLoaders = { + '.js': loadEsm, + '.mjs': loadEsm, +} + sade2 .version(version) .describe( @@ -143,20 +159,29 @@ sade2 'File extensions allowed in the bundle. (default js,cjs,mjs,ts,tsx)' ) .option('--config', 'Path to the config file') - .action((input, opts) => { + .action(async (input, opts) => { let config try { if (opts.config) { - config = lilconfigSync('playwright-test').load( - path.resolve(opts.config) - ) + config = await lilconfig('playwright-test', { + loaders: configLoaders, + }).load(path.resolve(opts.config)) } else { - config = lilconfigSync('playwright-test').search() + config = await lilconfig('playwright-test', { + loaders: configLoaders, + }).search() if (!config) { - config = lilconfigSync('pw-test').search() + config = await lilconfig('pw-test', { + loaders: configLoaders, + }).search() } } + // if the supplied config module was a function, invoke it + if (config && typeof config.config === 'function') { + config.config = await config.config() + } + let Runner switch (opts.runner) { diff --git a/mocks/sw/sw.config.mjs b/mocks/sw/sw.config.mjs new file mode 100644 index 00000000..dbef4f5d --- /dev/null +++ b/mocks/sw/sw.config.mjs @@ -0,0 +1,10 @@ +const path = require('path') + +export default { + buildSWConfig: { + inject: [path.join(__dirname, 'sw-globals.js')], + }, + afterTests: () => { + console.log('AFTER') + } +} diff --git a/mocks/sw/sw.function.config.mjs b/mocks/sw/sw.function.config.mjs new file mode 100644 index 00000000..6c65a093 --- /dev/null +++ b/mocks/sw/sw.function.config.mjs @@ -0,0 +1,12 @@ +const path = require('path') + +export default function () { + return { + buildSWConfig: { + inject: [path.join(__dirname, 'sw-globals.js')], + }, + afterTests: () => { + console.log('AFTER') + } + } +} diff --git a/mocks/sw/sw.promise.config.mjs b/mocks/sw/sw.promise.config.mjs new file mode 100644 index 00000000..47e0c02b --- /dev/null +++ b/mocks/sw/sw.promise.config.mjs @@ -0,0 +1,10 @@ +const path = require('path') + +export default Promise.resolve({ + buildSWConfig: { + inject: [path.join(__dirname, 'sw-globals.js')], + }, + afterTests: () => { + console.log('AFTER') + } +}) diff --git a/test.js b/test.js index 7ad382ba..9fdd3885 100644 --- a/test.js +++ b/test.js @@ -100,6 +100,42 @@ describe('mocha', function () { is(proc.exitCode, 0, 'exit code') }) + + it('supports esm config files', async () => { + const proc = await execa('./cli.js', [ + 'mocks/sw/sw-test.js', + '--sw', + 'mocks/sw/sw.js', + '--config', + 'mocks/sw/sw.config.mjs', + ]) + + is(proc.exitCode, 0, 'exit code') + }) + + it('supports esm config files that return promises', async () => { + const proc = await execa('./cli.js', [ + 'mocks/sw/sw-test.js', + '--sw', + 'mocks/sw/sw.js', + '--config', + 'mocks/sw/sw.promise.config.mjs', + ]) + + is(proc.exitCode, 0, 'exit code') + }) + + it('supports esm config files that return functions', async () => { + const proc = await execa('./cli.js', [ + 'mocks/sw/sw-test.js', + '--sw', + 'mocks/sw/sw.js', + '--config', + 'mocks/sw/sw.function.config.mjs', + ]) + + is(proc.exitCode, 0, 'exit code') + }) }) describe('tape', function () {