2022-04-25 09:30:14 -07:00
/ * *
* Copyright ( c ) Microsoft Corporation .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2023-09-21 12:40:18 -07:00
import http from 'http' ;
import https from 'https' ;
import url from 'url' ;
import type net from 'net' ;
import debugLogger from 'debug' ;
2022-04-25 09:30:14 -07:00
import path from 'path' ;
2023-09-21 12:40:18 -07:00
import fs from 'fs' ;
2023-01-13 13:50:38 -08:00
import { spawnAsync } from '../../packages/playwright-core/lib/utils/spawnAsync' ;
2022-04-25 09:30:14 -07:00
import { rimraf } from 'playwright-core/lib/utilsBundle' ;
2022-04-26 11:09:49 -07:00
import { TMP_WORKSPACES } from './npmTest' ;
2023-09-21 12:40:18 -07:00
import { createHttpServer } from '../../packages/playwright-core/lib/utils/network' ;
import { calculateSha1 } from '../../packages/playwright-core/lib/utils/crypto' ;
2022-04-25 09:30:14 -07:00
const PACKAGE_BUILDER_SCRIPT = path . join ( __dirname , '..' , '..' , 'utils' , 'pack_package.js' ) ;
2023-09-21 12:40:18 -07:00
const BROWSERS_CACHE_DIR = path . join ( TMP_WORKSPACES , 'npm-test-browsers-cache' ) ;
const debug = debugLogger ( 'itest' ) ;
2022-04-25 09:30:14 -07:00
async function globalSetup() {
2023-07-18 10:58:07 -07:00
await rimraf ( TMP_WORKSPACES ) ;
2022-04-26 11:09:49 -07:00
console . log ( ` Temporary workspaces will be created in ${ TMP_WORKSPACES } . They will not be removed at the end. Set DEBUG=itest to determine which sub-dir a specific test is using. ` ) ;
await fs . promises . mkdir ( TMP_WORKSPACES , { recursive : true } ) ;
2022-09-09 15:25:42 -07:00
2022-04-25 09:30:14 -07:00
if ( process . env . PWTEST_INSTALLATION_TEST_SKIP_PACKAGE_BUILDS ) {
console . log ( 'Skipped building packages. Unset PWTEST_INSTALLATION_TEST_SKIP_PACKAGE_BUILDS to build packages.' ) ;
2022-09-09 15:25:42 -07:00
} else {
console . log ( 'Building packages. Set PWTEST_INSTALLATION_TEST_SKIP_PACKAGE_BUILDS to skip.' ) ;
const outputDir = path . join ( __dirname , 'output' ) ;
2023-07-18 10:58:07 -07:00
await rimraf ( outputDir ) ;
2022-09-09 15:25:42 -07:00
await fs . promises . mkdir ( outputDir , { recursive : true } ) ;
const build = async ( buildTarget : string , pkgNameOverride? : string ) = > {
const outPath = path . resolve ( path . join ( outputDir , ` ${ buildTarget } .tgz ` ) ) ;
const { code , stderr , stdout } = await spawnAsync ( 'node' , [ PACKAGE_BUILDER_SCRIPT , buildTarget , outPath ] ) ;
if ( ! ! code )
throw new Error ( ` Failed to build: ${ buildTarget } : \ n ${ stderr } \ n ${ stdout } ` ) ;
console . log ( 'Built:' , pkgNameOverride || buildTarget ) ;
return [ pkgNameOverride || buildTarget , outPath ] ;
} ;
2022-04-25 09:30:14 -07:00
2022-09-09 15:25:42 -07:00
const builds = await Promise . all ( [
build ( 'playwright-core' ) ,
build ( 'playwright-test' , '@playwright/test' ) ,
build ( 'playwright' ) ,
build ( 'playwright-chromium' ) ,
build ( 'playwright-firefox' ) ,
build ( 'playwright-webkit' ) ,
2023-08-27 07:24:35 -07:00
build ( 'playwright-browser-chromium' , '@playwright/browser-chromium' ) ,
build ( 'playwright-browser-firefox' , '@playwright/browser-firefox' ) ,
build ( 'playwright-browser-webkit' , '@playwright/browser-webkit' ) ,
2022-09-09 15:25:42 -07:00
] ) ;
2022-04-25 09:30:14 -07:00
2022-09-09 15:25:42 -07:00
await fs . promises . writeFile ( path . join ( __dirname , '.registry.json' ) , JSON . stringify ( Object . fromEntries ( builds ) ) ) ;
}
2023-09-21 12:40:18 -07:00
const cdnProxyServer = createHttpServer ( async ( request : http.IncomingMessage , response : http.ServerResponse ) = > {
const requestedPath = url . parse ( request . url ! ) . path ;
const cachedPath = path . join ( BROWSERS_CACHE_DIR , calculateSha1 ( requestedPath ) ) ;
const cachedPathMetaInfo = cachedPath + '.metainfo' ;
if ( ! fs . existsSync ( cachedPath ) ) {
const realUrl = 'https://playwright.azureedge.net' + requestedPath ;
debug ( ` [cdn proxy] downloading ${ realUrl } headers= ${ JSON . stringify ( request . headers ) } ` ) ;
const headers = { . . . request . headers } ;
delete headers [ 'host' ] ;
const options = {
. . . url . parse ( realUrl ) ,
method : request.method ,
headers ,
} ;
const factory = options . protocol === 'https:' ? https : http ;
let doneCallback = ( ) = > { } ;
const donePromise = new Promise < void > ( f = > doneCallback = ( ) = > {
debug ( ` [cdn proxy] downloading ${ realUrl } finished ` ) ;
f ( ) ;
} ) ;
const realRequest = factory . request ( options , ( realResponse : http.IncomingMessage ) = > {
const metaInfo = {
statusCode : realResponse.statusCode ,
statusMessage : realResponse.statusMessage || '' ,
headers : realResponse.headers || { } ,
} ;
debug ( ` [cdn proxy] downloading ${ realUrl } statusCode= ${ realResponse . statusCode } ` ) ;
fs . mkdirSync ( path . dirname ( cachedPathMetaInfo ) , { recursive : true } ) ;
fs . writeFileSync ( cachedPathMetaInfo , JSON . stringify ( metaInfo ) ) ;
realResponse . pipe ( fs . createWriteStream ( cachedPath , { highWaterMark : 1024 * 1024 } ) ) . on ( 'close' , doneCallback ) . on ( 'finish' , doneCallback ) . on ( 'error' , doneCallback ) ;
} ) ;
request . pipe ( realRequest ) ;
await donePromise ;
}
const metaInfo = JSON . parse ( fs . readFileSync ( cachedPathMetaInfo , 'utf-8' ) ) ;
response . writeHead ( metaInfo . statusCode , metaInfo . statusMessage , metaInfo . headers ) ;
const done = ( ) = > {
debug ( ` [cdn proxy] serving ${ request . url ! } finished ` ) ;
response . end ( ) ;
} ;
fs . createReadStream ( cachedPath , { highWaterMark : 1024 * 1024 } ) . pipe ( response ) . on ( 'close' , done ) . on ( 'error' , done ) ;
debug ( ` [cdn proxy] serving ${ request . url ! } from cached ${ cachedPath } ` ) ;
} ) ;
cdnProxyServer . listen ( 0 ) ;
await new Promise ( f = > cdnProxyServer . once ( 'listening' , f ) ) ;
process . env . CDN_PROXY_HOST = ` http://127.0.0.1: ${ ( cdnProxyServer . address ( ) as net . AddressInfo ) . port } ` ;
console . log ( 'Stared CDN proxy at ' + process . env . CDN_PROXY_HOST ) ;
return async ( ) = > {
await new Promise ( f = > cdnProxyServer . close ( f ) ) ;
} ;
2022-04-25 09:30:14 -07:00
}
export default globalSetup ;