2021-03-25 12:40:04 +00:00
'use strict'
const fs = require ( 'fs' )
const http = require ( 'http' )
const path = require ( 'path' )
const pkgJson = require ( '../../../package.json' )
2022-04-20 21:55:44 +00:00
require ( 'dotenv' ) . config ( )
2021-03-25 12:40:04 +00:00
const rollup = require ( 'rollup' )
const resolve = require ( '@rollup/plugin-node-resolve' ) . nodeResolve
const replace = require ( '@rollup/plugin-replace' )
2022-04-20 21:55:44 +00:00
const typescriptPlugin = require ( '@rollup/plugin-typescript' )
2021-03-25 12:40:04 +00:00
const commonjs = require ( '@rollup/plugin-commonjs' )
2022-04-20 21:55:44 +00:00
const json = require ( '@rollup/plugin-json' )
2023-04-11 09:01:32 +00:00
const multi = require ( '@rollup/plugin-multi-entry' )
2022-10-03 17:57:08 +00:00
const runScript = require ( '../../run-script.cjs' )
2021-03-25 12:40:04 +00:00
const rootDir = path . join ( _ _dirname , '..' , '..' , '..' )
const regex = /^(?:(?<scope>@.*?)\/)?(?<name>.*)/ // We are going to take only the package name part if there is a scope, e.g. @my-org/package-name
const { name } = pkgJson . name . match ( regex ) . groups
const indexHtml = ` <!DOCTYPE html>
< html >
< head >
< meta http - equiv = "content-type" content = "text/html; charset=utf-8" / >
< title > $ { name } < / t i t l e >
< script src = "/mocha.js" > < / s c r i p t >
< script src = "/chai.js" > < / s c r i p t >
< / h e a d >
< body >
< / b o d y >
< div id = "mocha" > < / d i v >
< script >
mocha . setup ( {
ui : 'bdd' ,
reporter : 'spec' ,
color : 'true' ,
timeout : 90000
} )
< / s c r i p t >
2022-04-20 21:55:44 +00:00
< script type = "module" >
2021-03-25 12:40:04 +00:00
import './tests.js'
window . _mocha = mocha . run ( )
< / s c r i p t >
< / h t m l > `
2022-04-20 21:55:44 +00:00
const tsBundleOptions = {
tsconfig : path . join ( rootDir , 'tsconfig.json' ) ,
2023-04-11 09:01:32 +00:00
outDir : undefined , // ignore outDir in tsconfig.json
sourceMap : false
// include: ['build/typings/is-browser.d.ts']
2022-04-20 21:55:44 +00:00
}
async function buildTests ( testFiles ) {
2021-03-25 12:40:04 +00:00
// create a bundle
const inputOptions = {
2023-04-11 09:01:32 +00:00
input : testFiles ,
2021-03-25 12:40:04 +00:00
plugins : [
2023-04-11 09:01:32 +00:00
multi ( ) ,
2022-10-03 17:57:08 +00:00
replace ( {
'#pkg' : ` / ${ name } .esm.js ` ,
delimiters : [ '' , '' ] ,
preventAssignment : true
} ) ,
2021-03-25 12:40:04 +00:00
replace ( {
IS _BROWSER : true ,
2023-04-11 09:01:32 +00:00
_MODULE _TYPE : "'ESM'" ,
2021-03-25 12:40:04 +00:00
preventAssignment : true
} ) ,
2022-04-20 21:55:44 +00:00
typescriptPlugin ( tsBundleOptions ) ,
2021-03-25 12:40:04 +00:00
resolve ( {
browser : true ,
2023-04-11 09:01:32 +00:00
exportConditions : [ 'browser' , 'default' ] ,
mainFields : [ 'browser' , 'module' , 'main' ]
2021-03-25 12:40:04 +00:00
} ) ,
2022-04-20 21:55:44 +00:00
commonjs ( ) ,
json ( )
2021-08-06 08:10:32 +00:00
] ,
2022-10-03 17:57:08 +00:00
external : [ ` / ${ name } .esm.js ` ]
2021-03-25 12:40:04 +00:00
}
const bundle = await rollup . rollup ( inputOptions )
2023-04-11 09:01:32 +00:00
const { output } = await bundle . generate ( { format : 'es' } )
2021-03-25 12:40:04 +00:00
await bundle . close ( )
2022-04-20 21:55:44 +00:00
let bundledCode = output [ 0 ] . code
const replacements = _getEnvVarsReplacements ( bundledCode )
for ( const replacement in replacements ) {
2022-10-03 17:57:08 +00:00
const regExp = new RegExp ( replacement , 'g' )
bundledCode = bundledCode . replace ( regExp , replacements [ replacement ] )
2022-04-20 21:55:44 +00:00
}
return bundledCode
2021-03-25 12:40:04 +00:00
}
class TestServer {
constructor ( ) {
this . server = http . createServer ( )
}
2022-04-20 21:55:44 +00:00
async init ( testFiles ) {
2022-10-03 17:57:08 +00:00
/** Let us first check if the necessary files are built, and if not, build */
2023-04-11 09:01:32 +00:00
if ( ! fs . existsSync ( pkgJson . exports [ './esm-browser-bundle-nomin' ] ) ) {
2022-10-03 17:57:08 +00:00
await runScript ( path . join ( rootDir , 'node_modules' , '.bin' , 'rollup' ) , [ '-c' , 'build/rollup.config.js' ] )
}
2022-04-20 21:55:44 +00:00
const tests = await buildTests ( testFiles )
2021-03-25 12:40:04 +00:00
this . server . on ( 'request' , function ( req , res ) {
if ( req . url === ` / ${ name } .esm.js ` ) {
2023-04-11 09:01:32 +00:00
fs . readFile ( path . join ( rootDir , pkgJson . exports [ './esm-browser-bundle-nomin' ] ) , function ( err , data ) {
2021-03-25 12:40:04 +00:00
if ( err ) {
res . writeHead ( 404 )
res . end ( JSON . stringify ( err ) )
return
}
res . writeHead ( 200 , { 'Content-Type' : 'text/javascript' } )
res . end ( data )
} )
} else if ( req . url === '/index.html' || req . url === '/' ) {
res . writeHead ( 200 )
res . end ( indexHtml )
} else if ( req . url === '/tests.js' ) {
res . writeHead ( 200 , { 'Content-Type' : 'text/javascript' } )
res . end ( tests )
} else if ( req . url === '/mocha.js' ) {
fs . readFile ( path . join ( rootDir , 'node_modules/mocha/mocha.js' ) , function ( err , data ) {
if ( err ) {
res . writeHead ( 404 )
res . end ( JSON . stringify ( err ) )
return
}
res . writeHead ( 200 , { 'Content-Type' : 'text/javascript' } )
res . end ( data )
} )
2023-04-11 09:01:32 +00:00
} else if ( req . url === '/mocha.js.map' ) {
fs . readFile ( path . join ( rootDir , 'node_modules/mocha/mocha.js.map' ) , function ( err , data ) {
if ( err ) {
res . writeHead ( 404 )
res . end ( JSON . stringify ( err ) )
return
}
res . writeHead ( 200 , { 'Content-Type' : 'text/javascript' } )
res . end ( data )
} )
2021-03-25 12:40:04 +00:00
} else if ( req . url === '/chai.js' || req . url === '/chai' ) {
fs . readFile ( path . join ( rootDir , 'node_modules/chai/chai.js' ) , function ( err , data ) {
if ( err ) {
res . writeHead ( 404 )
res . end ( JSON . stringify ( err ) )
return
}
res . writeHead ( 200 , { 'Content-Type' : 'text/javascript' } )
res . end ( data )
} )
2023-04-11 09:01:32 +00:00
} else if ( req . url === '/favicon.ico' ) {
fs . readFile ( path . join ( _ _dirname , 'favicon.ico' ) , function ( err , data ) {
if ( err ) {
res . writeHead ( 404 )
res . end ( JSON . stringify ( err ) )
return
}
res . writeHead ( 200 , { 'Content-Type' : 'application/ico' } )
res . end ( data )
} )
2021-03-25 12:40:04 +00:00
} else {
res . writeHead ( 404 )
res . end ( )
}
} )
}
listen ( port = 38080 ) {
return new Promise ( ( resolve , reject ) => {
this . server . listen ( port , error => {
if ( error ) return reject ( error )
console . log ( ` Testing server listenning at http://localhost: ${ port } ` )
return resolve ( )
} )
} )
}
close ( ) {
return new Promise ( ( resolve , reject ) => {
this . server . close ( error => ( error ) ? reject ( error ) : resolve ( ) )
} )
}
}
2022-04-20 21:55:44 +00:00
function _getEnvVarsReplacements ( testsCode ) {
const replacements = { }
const missingEnvVars = [ ]
for ( const match of testsCode . matchAll ( /process\.env\.(\w+)/g ) ) {
const envVar = match [ 1 ]
if ( process . env [ envVar ] !== undefined ) {
replacements [ match [ 0 ] ] = '`' + process . env [ envVar ] + '`'
} else {
2023-04-11 09:01:32 +00:00
replacements [ match [ 0 ] ] = undefined
2022-04-20 21:55:44 +00:00
}
}
for ( const match of testsCode . matchAll ( /process\.env\[['"](\w+)['"]\]/g ) ) {
const envVar = match [ 1 ]
if ( process . env [ envVar ] !== undefined ) {
replacements [ match [ 0 ] ] = '`' + process . env [ envVar ] + '`'
} else {
2023-04-11 09:01:32 +00:00
replacements [ match [ 0 ] ] = undefined
2022-04-20 21:55:44 +00:00
}
}
if ( missingEnvVars . length > 0 ) {
2023-04-11 09:01:32 +00:00
console . warn ( 'The folloinwg environment variables are missing in your .env file and will be replaced with "undefined": ' + [ ... ( new Set ( missingEnvVars ) ) . values ( ) ] . join ( ', ' ) )
2022-04-20 21:55:44 +00:00
}
return replacements
}
2021-03-25 12:40:04 +00:00
exports . server = new TestServer ( )