Skip to content

Commit

Permalink
Update CI/test set up (#9499)
Browse files Browse the repository at this point in the history
* Disable concurrency for tests

* Add browser instance sharing

* Bump concurrency and install chromedriver smoother

* Fix config typo

* Fix local test

* Limit azure concurrency again

* Add delay for empty-object-test

* Make sure to use open port for chromedriver

* Move browser closing to jest-environment

* Re-enable concurrency for Azure

* bump

* Disable concurrency for Azure again

* Re-enable concurrency for Azure

* bump
  • Loading branch information
ijjk authored and Timer committed Nov 25, 2019
1 parent 77c4b4d commit b058427
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 161 deletions.
6 changes: 4 additions & 2 deletions .circleci/config.yml
Expand Up @@ -38,9 +38,11 @@ commands:
command: yarn install --frozen-lockfile --check-files
- run:
name: Install correct Chrome Driver version
command: yarn add chromedriver@76 -W && git checkout yarn.lock package.json
command: node node_modules/chromedriver/install.js
environment:
CHROMEDRIVER_VERSION: '76.0.3809.68'
- run: google-chrome --version
- run: chromedriver --version
- run: yarn chromedriver --version
yarn_lint:
steps:
- run:
Expand Down
4 changes: 2 additions & 2 deletions azure-pipelines.yml
Expand Up @@ -39,9 +39,9 @@ steps:
displayName: 'Install dependencies'
- script: |
yarn add chromedriver@76 -W
node node_modules/chromedriver/install.js
displayName: 'Install correct Chrome Driver version'
- script: |
node run-tests.js -c 2 -g $(group)
node run-tests.js -g $(group)
displayName: 'Run tests'
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -8,8 +8,8 @@
"lerna": "lerna",
"dev": "lerna run build --stream --parallel",
"dev2": "while true; do yarn --check-files && yarn dev; done",
"testonly": "jest",
"testall": "yarn run testonly -- --ci --reporters=default --reporters=jest-junit --forceExit --runInBand",
"testonly": "jest --runInBand",
"testall": "yarn run testonly -- --ci --reporters=default --reporters=jest-junit --forceExit",
"pretest": "yarn run lint",
"git-reset": "git reset --hard HEAD",
"git-clean": "git clean -d -x -e node_modules -e packages -f",
Expand Down
Expand Up @@ -49,6 +49,7 @@ describe('Empty Project', () => {

it('should show empty object warning during client transition', async () => {
const browser = await webdriver(appPort, '/static')
await waitFor(1000)
await browser.eval(`(function() {
window.gotWarn = false
const origWarn = console.warn
Expand All @@ -60,7 +61,7 @@ describe('Empty Project', () => {
}
window.next.router.replace('/another')
})()`)
await waitFor(300)
await waitFor(1000)
const gotWarn = await browser.eval(`window.gotWarn`)
expect(gotWarn).toBe(true)
await browser.close()
Expand Down
4 changes: 3 additions & 1 deletion test/integration/future/test/index.test.js
Expand Up @@ -36,7 +36,9 @@ describe('future.excludeDefaultMomentLocales', () => {
const browser = await webdriver(appPort, '/')
await waitFor(5000)
expect(await browser.elementByCss('h1').text()).toMatch(/current time/i)
expect(await browser.eval('moment.locales()')).toStrictEqual(['en'])
const locales = await browser.eval('moment.locales()')
expect(locales).toEqual(['en'])
expect(locales.length).toBe(1)
await browser.close()
})
})
86 changes: 61 additions & 25 deletions test/jest-environment.js
Expand Up @@ -4,6 +4,8 @@ const os = require('os')
const http = require('http')
const fetch = require('node-fetch')
const getPort = require('get-port')
const waitPort = require('wait-port')
const chromedriver = require('chromedriver')
const NodeEnvironment = require('jest-environment-node')
const {
BROWSER_NAME,
Expand All @@ -16,8 +18,14 @@ let browser
let initialWindow
let browserOptions = {
browserName: BROWSER_NAME || 'chrome',
...(process.env.HEADLESS === 'true'
? {
chromeOptions: { args: ['--headless'] },
}
: {}),
}
let deviceIP = 'localhost'
let driverPort = '9515'

const isIE = BROWSER_NAME === 'ie'
const isSafari = BROWSER_NAME === 'safari'
Expand Down Expand Up @@ -75,38 +83,52 @@ const newTabPg = `
class CustomEnvironment extends NodeEnvironment {
async createBrowser() {
// always create new browser session if not BrowserStack
if (!browser && isBrowserStack) {
if (!browser) {
if (!isBrowserStack) {
driverPort = await getPort()
chromedriver.start([`--port=${driverPort}`])

// https://github.com/giggio/node-chromedriver/issues/117
await waitPort({
port: driverPort,
timeout: 1000 * 60 * 2, // 2 Minutes
})
}

browser = wd.promiseChainRemote(
'hub-cloud.browserstack.com', // seleniumHost
80, // seleniumPort
BROWSERSTACK_USERNAME,
BROWSERSTACK_ACCESS_KEY
...(isBrowserStack
? [
'hub-cloud.browserstack.com', // seleniumHost
80, // seleniumPort
BROWSERSTACK_USERNAME,
BROWSERSTACK_ACCESS_KEY,
]
: [`http://localhost:${driverPort}`])
)

// Setup the browser instance
await browser.init(browserOptions)
initialWindow = await browser.windowHandle()
global.bsBrowser = browser
}

if (isBrowserStack) {
// disable browser.close and we handle it manually
browser.origClose = browser.close
browser.close = () => {}
// Since ie11 doesn't like dataURIs we have to spin up a
// server to handle the new tab page
this.server = http.createServer((req, res) => {
res.statusCode = 200
res.end(newTabPg)
})
this.newTabPort = await getPort()
await new Promise((resolve, reject) => {
this.server.listen(this.newTabPort, err => {
if (err) return reject(err)
resolve()
})
// disable browser.close and we handle it manually
browser.origClose = browser.close
browser.close = () => {}
// Since ie11 doesn't like dataURIs we have to spin up a
// server to handle the new tab page
this.server = http.createServer((req, res) => {
res.statusCode = 200
res.end(newTabPg)
})
this.newTabPort = await getPort()
await new Promise((resolve, reject) => {
this.server.listen(this.newTabPort, err => {
if (err) return reject(err)
resolve()
})
})

if (isBrowserStack) {
const networkIntfs = os.networkInterfaces()
// find deviceIP to use with BrowserStack
for (const intf of Object.keys(networkIntfs)) {
Expand All @@ -124,13 +146,14 @@ class CustomEnvironment extends NodeEnvironment {
}
}
}

this.global.browserName = browserOptions.browserName
this.global.isBrowserStack = isBrowserStack

// Mock current browser set up
this.global.bsWd = async (appPort, pathname) => {
this.global.sharedWD = async (appPort, pathname) => {
const url = `http://${deviceIP}:${appPort}${pathname}`
console.log(`\n> Loading browser with ${url}\n`)
if (isBrowserStack) await this.freshWindow()
await this.freshWindow()

return new Promise((resolve, reject) => {
let timedOut = false
Expand Down Expand Up @@ -199,6 +222,19 @@ class CustomEnvironment extends NodeEnvironment {
async teardown() {
await super.teardown()
if (this.server) this.server.close()
if (browser) {
// Close all remaining browser windows
try {
const windows = await browser.windowHandles()
for (const window of windows) {
if (!window) continue
await browser.window(window)
await browser.origClose()
await browser.quit()
}
} catch (_) {}
}
chromedriver.stop()
}
}

Expand Down
17 changes: 2 additions & 15 deletions test/jest-global-setup.js
@@ -1,4 +1,4 @@
let globalSetup
let globalSetup = () => {}

if (process.env.BROWSERSTACK) {
const { Local } = require('browserstack-local')
Expand All @@ -18,19 +18,6 @@ if (process.env.BROWSERSTACK) {
})
})
}
} else {
const chromedriver = require('chromedriver')
const waitPort = require('wait-port')

globalSetup = async function globalSetup() {
chromedriver.start()

// https://github.com/giggio/node-chromedriver/issues/117
await waitPort({
port: 9515,
timeout: 1000 * 60 * 2, // 2 Minutes
})
}
}

module.exports = () => globalSetup()
module.exports = globalSetup
17 changes: 1 addition & 16 deletions test/jest-global-teardown.js
@@ -1,24 +1,9 @@
let globalTeardown = () => {}
const browser = global.bsBrowser

if (process.env.BROWSERSTACK) {
globalTeardown = () => global.browserStackLocal.killAllProcesses(() => {})
}

module.exports = async () => {
if (browser) {
// Close all remaining browser windows
try {
const windows = await browser.windowHandles()
for (const window of windows) {
if (!window) continue
await browser.window(window)
await browser.origClose()
await browser.quit()
await globalTeardown()
}
} catch (_) {}
} else {
await globalTeardown()
}
await globalTeardown()
}
98 changes: 1 addition & 97 deletions test/lib/next-webdriver.js
@@ -1,97 +1 @@
import wd from 'wd'
import getPort from 'get-port'
import waitPort from 'wait-port'

const doHeadless = process.env.HEADLESS !== 'false'
let driverPort = 9515

let webdriver = async function(appPort, pathname) {
if (typeof appPort === 'undefined') {
throw new Error('appPort is undefined')
}

const url = `http://localhost:${appPort}${pathname}`
console.log(`> Start loading browser with url: ${url}`)

// Sometimes browser won't initialize due to some random issues.
// So, we need to timeout the initialization and retry again.
for (let lc = 0; lc < 5; lc++) {
try {
const browser = await getBrowser(url, 5000)
console.log(`> Complete loading browser with url: ${url}`)
return browser
} catch (ex) {
console.warn(`> Error when loading browser with url: ${url}`)

// Try restarting chromedriver max twice
if (lc < 2) {
const chromedriver = require('chromedriver')
console.log('Trying to restart chromedriver with random port')
driverPort = await getPort()
chromedriver.stop()
chromedriver.start([`--port=${driverPort}`])
// https://github.com/giggio/node-chromedriver/issues/117
await waitPort({
port: driverPort,
timeout: 1000 * 30, // 30 seconds
})
continue
}

if (ex.message === 'TIMEOUT') continue
throw ex
}
}

console.error(`> Tried 5 times. Cannot load the browser for url: ${url}`)
throw new Error(`Couldn't start the browser for url: ${url}`)
}

function getBrowser(url, timeout) {
const browser = wd.promiseChainRemote(`http://localhost:${driverPort}/`)

return new Promise((resolve, reject) => {
let timeouted = false
const timeoutHandler = setTimeout(() => {
timeouted = true
const error = new Error('TIMEOUT')
reject(error)
}, timeout)

browser
.init({
browserName: 'chrome',
...(doHeadless
? {
chromeOptions: { args: ['--headless'] },
}
: {}),
})
.get(url, err => {
if (timeouted) {
try {
browser.close(() => {
// Ignore errors
})
} catch (err) {
// Ignore
}
return
}

clearTimeout(timeoutHandler)

if (err) {
reject(err)
return
}

resolve(browser)
})
})
}

if (global.isBrowserStack) {
webdriver = (...args) => global.bsWd(...args)
}
export default webdriver
export default global.sharedWD

0 comments on commit b058427

Please sign in to comment.