diff --git a/package.json b/package.json
index 94c20b43..8941c970 100644
--- a/package.json
+++ b/package.json
@@ -128,7 +128,7 @@
"babel-jest": "23.4.2",
"benchmark": "2.1.4",
"cheerio": "0.22.0",
- "chromedriver": "2.32.3",
+ "chromedriver": "2.42.0",
"clone": "2.1.1",
"coveralls": "2.13.1",
"cross-env": "5.2.0",
diff --git a/test/integration/basic/test/error-recovery.js b/test/integration/basic/test/error-recovery.js
index 19f4c9c4..fd76db4b 100644
--- a/test/integration/basic/test/error-recovery.js
+++ b/test/integration/basic/test/error-recovery.js
@@ -1,10 +1,42 @@
/* global describe, it, expect */
import webdriver from 'next-webdriver'
import { join } from 'path'
-import { check, File, getReactErrorOverlayContent } from 'next-test-utils'
+import { check, File, waitFor, getReactErrorOverlayContent, getBrowserBodyText } from 'next-test-utils'
export default (context, render) => {
describe('Error Recovery', () => {
+ it('should recover from 404 after a page has been added', async () => {
+ let browser
+ const newPage = new File(join(__dirname, '../', 'pages', 'hmr', 'new-page.js'))
+ try {
+ browser = await webdriver(context.appPort, '/hmr/new-page')
+
+ expect(await browser.elementByCss('body').text()).toMatch(/This page could not be found/)
+
+ // Add the page
+ newPage.write('export default () => (
the-new-page
)')
+
+ await check(
+ () => getBrowserBodyText(browser),
+ /the-new-page/
+ )
+
+ newPage.delete()
+
+ await check(
+ () => getBrowserBodyText(browser),
+ /This page could not be found/
+ )
+ } catch (err) {
+ newPage.delete()
+ throw err
+ } finally {
+ if (browser) {
+ browser.close()
+ }
+ }
+ })
+
it('should have installed the react-overlay-editor editor handler', async () => {
let browser
const aboutPage = new File(join(__dirname, '../', 'pages', 'hmr', 'about.js'))
@@ -19,12 +51,20 @@ export default (context, render) => {
aboutPage.restore()
await check(
- () => browser.elementByCss('body').text(),
+ () => getBrowserBodyText(browser),
/This is the about page/
)
- } finally {
+ } catch (err) {
aboutPage.restore()
+ if (browser) {
+ await check(
+ () => getBrowserBodyText(browser),
+ /This is the about page/
+ )
+ }
+ throw err
+ } finally {
if (browser) {
browser.close()
}
@@ -36,8 +76,7 @@ export default (context, render) => {
const aboutPage = new File(join(__dirname, '../', 'pages', 'hmr', 'about.js'))
try {
browser = await webdriver(context.appPort, '/hmr/about')
- const text = await browser
- .elementByCss('p').text()
+ const text = await browser.elementByCss('p').text()
expect(text).toBe('This is the about page.')
aboutPage.replace('', 'div')
@@ -47,12 +86,20 @@ export default (context, render) => {
aboutPage.restore()
await check(
- () => browser.elementByCss('body').text(),
+ () => getBrowserBodyText(browser),
/This is the about page/
)
- } finally {
+ } catch (err) {
aboutPage.restore()
+ if (browser) {
+ await check(
+ () => getBrowserBodyText(browser),
+ /This is the about page/
+ )
+ }
+ throw err
+ } finally {
if (browser) {
browser.close()
}
@@ -72,9 +119,19 @@ export default (context, render) => {
aboutPage.restore()
await check(
- () => browser.elementByCss('body').text(),
+ () => getBrowserBodyText(browser),
/This is the contact page/
)
+ } catch (err) {
+ aboutPage.restore()
+ if (browser) {
+ await check(
+ () => getBrowserBodyText(browser),
+ /This is the contact page/
+ )
+ }
+
+ throw err
} finally {
aboutPage.restore()
if (browser) {
@@ -99,7 +156,7 @@ export default (context, render) => {
aboutPage.restore()
await check(
- () => browser.elementByCss('body').text(),
+ () => getBrowserBodyText(browser),
/This is the about page/
)
} finally {
@@ -111,137 +168,195 @@ export default (context, render) => {
})
it('should recover from errors in the render function', async () => {
- const browser = await webdriver(context.appPort, '/hmr/about')
- const text = await browser
- .elementByCss('p').text()
- expect(text).toBe('This is the about page.')
-
+ let browser
const aboutPage = new File(join(__dirname, '../', 'pages', 'hmr', 'about.js'))
- aboutPage.replace('return', 'throw new Error("an-expected-error");\nreturn')
+ try {
+ browser = await webdriver(context.appPort, '/hmr/about')
+ const text = await browser.elementByCss('p').text()
- expect(await getReactErrorOverlayContent(browser)).toMatch(/an-expected-error/)
+ expect(text).toBe('This is the about page.')
- aboutPage.restore()
+ aboutPage.replace('return', 'throw new Error("an-expected-error");\nreturn')
- await check(
- () => browser.elementByCss('body').text(),
- /This is the about page/
- )
+ expect(await getReactErrorOverlayContent(browser)).toMatch(/an-expected-error/)
- browser.close()
+ aboutPage.restore()
+
+ await check(
+ () => getBrowserBodyText(browser),
+ /This is the about page/
+ )
+ } catch (err) {
+ aboutPage.restore()
+ if (browser) {
+ await check(
+ () => getBrowserBodyText(browser),
+ /This is the about page/
+ )
+ }
+
+ throw err
+ } finally {
+ if (browser) {
+ browser.close()
+ }
+ }
})
it('should recover after exporting an invalid page', async () => {
- const browser = await webdriver(context.appPort, '/hmr/about')
- const text = await browser
- .elementByCss('p').text()
- expect(text).toBe('This is the about page.')
-
+ let browser
const aboutPage = new File(join(__dirname, '../', 'pages', 'hmr', 'about.js'))
- aboutPage.replace('export default', 'export default "not-a-page"\nexport const fn = ')
+ try {
+ browser = await webdriver(context.appPort, '/hmr/about')
+ const text = await browser.elementByCss('p').text()
+ expect(text).toBe('This is the about page.')
- await check(
- () => browser.elementByCss('body').text(),
- /The default export is not a React Component/
- )
+ aboutPage.replace('export default', 'export default "not-a-page"\nexport const fn = ')
- aboutPage.restore()
+ await check(
+ () => getBrowserBodyText(browser),
+ /The default export is not a React Component/
+ )
- await check(
- () => browser.elementByCss('body').text(),
- /This is the about page/
- )
+ aboutPage.restore()
- browser.close()
+ await check(
+ () => getBrowserBodyText(browser),
+ /This is the about page/
+ )
+ } catch (err) {
+ aboutPage.restore()
+
+ if (browser) {
+ await check(
+ () => getBrowserBodyText(browser),
+ /This is the about page/
+ )
+ }
+
+ throw err
+ } finally {
+ if (browser) {
+ browser.close()
+ }
+ }
})
it('should recover after a bad return from the render function', async () => {
- const browser = await webdriver(context.appPort, '/hmr/about')
- const text = await browser
- .elementByCss('p').text()
- expect(text).toBe('This is the about page.')
-
+ let browser
const aboutPage = new File(join(__dirname, '../', 'pages', 'hmr', 'about.js'))
- aboutPage.replace('export default', 'export default () => /search/ \nexport const fn = ')
+ try {
+ browser = await webdriver(context.appPort, '/hmr/about')
+ const text = await browser.elementByCss('p').text()
+ expect(text).toBe('This is the about page.')
- await check(
- () => browser.elementByCss('body').text(),
- /Objects are not valid as a React child/
- )
+ aboutPage.replace('export default', 'export default () => /search/ \nexport const fn = ')
- aboutPage.restore()
+ await check(
+ () => getBrowserBodyText(browser),
+ /Objects are not valid as a React child/
+ )
- await check(
- () => browser.elementByCss('body').text(),
- /This is the about page/
- )
+ aboutPage.restore()
- browser.close()
+ await check(
+ () => getBrowserBodyText(browser),
+ /This is the about page/
+ )
+ } catch (err) {
+ aboutPage.restore()
+
+ if (browser) {
+ await check(
+ () => getBrowserBodyText(browser),
+ /This is the about page/
+ )
+ }
+
+ throw err
+ } finally {
+ if (browser) {
+ browser.close()
+ }
+ }
})
it('should recover from errors in getInitialProps in client', async () => {
- const browser = await webdriver(context.appPort, '/hmr')
- await browser.elementByCss('#error-in-gip-link').click()
-
- expect(await getReactErrorOverlayContent(browser)).toMatch(/an-expected-error-in-gip/)
-
+ let browser
const erroredPage = new File(join(__dirname, '../', 'pages', 'hmr', 'error-in-gip.js'))
- erroredPage.replace('throw error', 'return {}')
+ try {
+ browser = await webdriver(context.appPort, '/hmr')
+ await browser.elementByCss('#error-in-gip-link').click()
- await check(
- () => browser.elementByCss('body').text(),
- /Hello/
- )
+ expect(await getReactErrorOverlayContent(browser)).toMatch(/an-expected-error-in-gip/)
- erroredPage.restore()
- browser.close()
+ erroredPage.replace('throw error', 'return {}')
+
+ await check(
+ () => getBrowserBodyText(browser),
+ /Hello/
+ )
+
+ erroredPage.restore()
+
+ await check(
+ async () => {
+ await browser.refresh()
+ const text = await browser.elementByCss('body').text()
+ if (text.includes('Hello')) {
+ await waitFor(2000)
+ throw new Error('waiting')
+ }
+ return getReactErrorOverlayContent(browser)
+ },
+ /an-expected-error-in-gip/
+ )
+ } catch (err) {
+ erroredPage.restore()
+
+ throw err
+ } finally {
+ if (browser) {
+ browser.close()
+ }
+ }
})
it('should recover after an error reported via SSR', async () => {
- const browser = await webdriver(context.appPort, '/hmr/error-in-gip')
-
- expect(await getReactErrorOverlayContent(browser)).toMatch(/an-expected-error-in-gip/)
-
- const erroredPage = new File(join(__dirname, '../', 'pages', 'hmr', 'error-in-gip.js'))
- erroredPage.replace('throw error', 'return {}')
-
- await check(
- () => browser.elementByCss('body').text(),
- /Hello/
- )
-
- erroredPage.restore()
- browser.close()
- })
-
- it('should recover from 404 after a page has been added', async () => {
let browser
- let newPage
+ const erroredPage = new File(join(__dirname, '../', 'pages', 'hmr', 'error-in-gip.js'))
try {
- browser = await webdriver(context.appPort, '/hmr/new-page')
+ browser = await webdriver(context.appPort, '/hmr/error-in-gip')
- expect(await browser.elementByCss('body').text()).toMatch(/This page could not be found/)
+ expect(await getReactErrorOverlayContent(browser)).toMatch(/an-expected-error-in-gip/)
- // Add the page
- newPage = new File(join(__dirname, '../', 'pages', 'hmr', 'new-page.js'))
- newPage.write('export default () => (the-new-page
)')
+ const erroredPage = new File(join(__dirname, '../', 'pages', 'hmr', 'error-in-gip.js'))
+ erroredPage.replace('throw error', 'return {}')
await check(
- () => {
- if (!browser.hasElementById('new-page')) {
- throw new Error('waiting')
- }
-
- return browser.elementByCss('body').text()
- },
- /the-new-page/
+ () => getBrowserBodyText(browser),
+ /Hello/
)
- // expect(await browser.elementByCss('body').text()).toMatch(/the-new-page/)
+ erroredPage.restore()
+
+ await check(
+ async () => {
+ await browser.refresh()
+ const text = await getBrowserBodyText(browser)
+ if (text.includes('Hello')) {
+ await waitFor(2000)
+ throw new Error('waiting')
+ }
+ return getReactErrorOverlayContent(browser)
+ },
+ /an-expected-error-in-gip/
+ )
+ } catch (err) {
+ erroredPage.restore()
+
+ throw err
} finally {
- if (newPage) {
- newPage.delete()
- }
if (browser) {
browser.close()
}
diff --git a/test/integration/config/test/client.js b/test/integration/config/test/client.js
index 6432857b..b116c7ad 100644
--- a/test/integration/config/test/client.js
+++ b/test/integration/config/test/client.js
@@ -1,7 +1,7 @@
/* global describe, it, expect */
import webdriver from 'next-webdriver'
-import { waitFor } from 'next-test-utils'
+import { waitFor, check, File } from 'next-test-utils'
import { readFileSync, writeFileSync } from 'fs'
import { join } from 'path'
@@ -10,7 +10,7 @@ export default (context, render) => {
it('should have config available on the client', async () => {
const browser = await webdriver(context.appPort, '/next-config')
// Wait for client side to load
- await waitFor(5000)
+ await waitFor(10000)
const serverText = await browser.elementByCss('#server-only').text()
const serverClientText = await browser.elementByCss('#server-and-client').text()
@@ -37,8 +37,7 @@ export default (context, render) => {
// Change the page
writeFileSync(pagePath, editedContent, 'utf8')
- // wait for 5 seconds
- await waitFor(5000)
+ await waitFor(10000)
try {
// Check whether the this page has reloaded or not.
@@ -59,36 +58,47 @@ export default (context, render) => {
})
it('should update sass styles using hmr', async () => {
+ const file = new File(join(__dirname, '../', 'components', 'hello-webpack-sass.scss'))
let browser
try {
browser = await webdriver(context.appPort, '/webpack-css')
- const pTag = await browser.elementByCss('.hello-world')
- const initialFontSize = await pTag.getComputedCss('color')
- expect(initialFontSize).toBe('rgba(255, 255, 0, 1)')
+ expect(
+ await browser.elementByCss('.hello-world').getComputedCss('color')
+ ).toBe('rgba(255, 255, 0, 1)')
- const pagePath = join(__dirname, '../', 'components', 'hello-webpack-sass.scss')
+ file.replace('yellow', 'red')
- const originalContent = readFileSync(pagePath, 'utf8')
- const editedContent = originalContent.replace('yellow', 'red')
+ await waitFor(10000)
- // Change the page
- writeFileSync(pagePath, editedContent, 'utf8')
+ await check(
+ async () => {
+ const tag = await browser.elementByCss('.hello-world')
+ const prop = await tag.getComputedCss('color')
- // wait for 5 seconds
- await waitFor(5000)
+ expect(prop).toBe('rgba(255, 0, 0, 1)')
+ return 'works'
+ },
+ /works/
+ )
- try {
- // Check whether the this page has reloaded or not.
- const editedPTag = await browser.elementByCss('.hello-world')
- const editedFontSize = await editedPTag.getComputedCss('color')
+ file.restore()
- expect(editedFontSize).toBe('rgba(255, 0, 0, 1)')
- } finally {
- // Finally is used so that we revert the content back to the original regardless of the test outcome
- // restore the about page content.
- writeFileSync(pagePath, originalContent, 'utf8')
- }
+ await waitFor(10000)
+
+ await check(
+ async () => {
+ const tag = await browser.elementByCss('.hello-world')
+ const prop = await tag.getComputedCss('color')
+ expect(prop).toBe('rgba(255, 255, 0, 1)')
+ return 'works'
+ },
+ /works/
+ )
+ } catch (err) {
+ file.restore()
+
+ throw err
} finally {
if (browser) {
browser.close()
diff --git a/test/integration/export/test/browser.js b/test/integration/export/test/browser.js
index d1bc169a..529c4eca 100644
--- a/test/integration/export/test/browser.js
+++ b/test/integration/export/test/browser.js
@@ -1,6 +1,6 @@
/* global describe, it, expect */
import webdriver from 'next-webdriver'
-import { waitFor } from 'next-test-utils'
+import { check } from 'next-test-utils'
export default function (context) {
describe('Render via browser', () => {
@@ -100,39 +100,36 @@ export default function (context) {
.elementByCss('#dynamic-imports-page').click()
.waitForElementByCss('#dynamic-imports-page')
- // Wait until browser loads the dynamic import chunk
- // TODO: We may need to find a better way to do this
- await waitFor(5000)
+ await check(
+ () => browser.elementByCss('#dynamic-imports-page p').text(),
+ /Welcome to dynamic imports/
+ )
- const text = await browser
- .elementByCss('#dynamic-imports-page p').text()
-
- expect(text).toBe('Welcome to dynamic imports.')
browser.close()
})
it('should render pages with url hash correctly', async () => {
- const browser = await webdriver(context.port, '/')
+ let browser
+ try {
+ browser = await webdriver(context.port, '/')
- // Check for the query string content
- const text = await browser
- .elementByCss('#with-hash').click()
- .waitForElementByCss('#dynamic-page')
- .elementByCss('#dynamic-page p').text()
+ // Check for the query string content
+ const text = await browser
+ .elementByCss('#with-hash').click()
+ .waitForElementByCss('#dynamic-page')
+ .elementByCss('#dynamic-page p').text()
- expect(text).toBe('zeit is awesome')
+ expect(text).toBe('zeit is awesome')
- // Check for the hash
- while (true) {
- const hashText = await browser
- .elementByCss('#hash').text()
-
- if (/cool/.test(hashText)) {
- break
+ await check(
+ () => browser.elementByCss('#hash').text(),
+ /cool/
+ )
+ } finally {
+ if (browser) {
+ browser.close()
}
}
-
- browser.close()
})
it('should navigate even if used a button inside ', async () => {
diff --git a/test/integration/ondemand/pages/nav/index.js b/test/integration/ondemand/pages/nav/index.js
index 0b873033..0f48260e 100644
--- a/test/integration/ondemand/pages/nav/index.js
+++ b/test/integration/ondemand/pages/nav/index.js
@@ -1,5 +1,7 @@
import Link from 'next/link'
export default () =>
diff --git a/test/integration/ondemand/test/index.test.js b/test/integration/ondemand/test/index.test.js
index a163409a..f8b8dda2 100644
--- a/test/integration/ondemand/test/index.test.js
+++ b/test/integration/ondemand/test/index.test.js
@@ -7,7 +7,9 @@ import {
findPort,
launchApp,
killApp,
- waitFor
+ waitFor,
+ check,
+ getBrowserBodyText
} from 'next-test-utils'
const context = {}
@@ -63,12 +65,13 @@ describe('On Demand Entries', () => {
let browser
try {
browser = await webdriver(context.appPort, '/nav')
- const text = await browser
- .elementByCss('#to-dynamic').click()
- .waitForElementByCss('.dynamic-page')
- .elementByCss('p').text()
- expect(text).toBe('Hello')
+ await browser.eval('document.getElementById("to-dynamic").click()')
+
+ await check(async () => {
+ const text = await getBrowserBodyText(browser)
+ return text
+ }, /Hello/)
} finally {
if (browser) {
browser.close()
diff --git a/test/lib/next-test-utils.js b/test/lib/next-test-utils.js
index d6cfe316..6673f373 100644
--- a/test/lib/next-test-utils.js
+++ b/test/lib/next-test-utils.js
@@ -152,7 +152,7 @@ export async function startStaticServer (dir) {
export async function check (contentFn, regex) {
let found = false
- setTimeout(async () => {
+ const timeout = setTimeout(async () => {
if (found) {
return
}
@@ -170,6 +170,7 @@ export async function check (contentFn, regex) {
const newContent = await contentFn()
if (regex.test(newContent)) {
found = true
+ clearTimeout(timeout)
break
}
await waitFor(1000)
@@ -231,3 +232,7 @@ export async function getReactErrorOverlayContent (browser) {
}
return browser.eval(`document.querySelector('iframe').contentWindow.document.body.innerHTML`)
}
+
+export function getBrowserBodyText (browser) {
+ return browser.eval('document.getElementsByTagName("body")[0].innerText')
+}