From 7739421e9216545b6c1a4a4b5ba11a83cc0cb915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Sun, 29 Oct 2017 14:59:38 +0100 Subject: [PATCH] test: Add puppeteer for testing (wip) --- package.json | 1 + test/basic.dom.test.js | 212 +++++++++++++++++++++++++++++++++++++++++ yarn.lock | 95 +++++++++++++++++- 3 files changed, 305 insertions(+), 3 deletions(-) create mode 100644 test/basic.dom.test.js diff --git a/package.json b/package.json index 9ae70b1ddb..d6397fdf3b 100644 --- a/package.json +++ b/package.json @@ -144,6 +144,7 @@ "jsdom": "^11.3.0", "json-loader": "^0.5.7", "nyc": "^11.2.1", + "puppeteer": "^0.12.0", "request": "^2.83.0", "request-promise-native": "^1.0.5", "rimraf": "^2.6.2", diff --git a/test/basic.dom.test.js b/test/basic.dom.test.js new file mode 100644 index 0000000000..992aadde17 --- /dev/null +++ b/test/basic.dom.test.js @@ -0,0 +1,212 @@ +import test from 'ava' +import { resolve } from 'path' +import puppeteer from 'puppeteer' +import { Nuxt, Builder } from '../index.js' + +const port = 4003 +const url = (route) => 'http://localhost:' + port + route + +let nuxt = null +let browser +const open = async (path) => { + const page = await browser.newPage() + await page.goto(url(path)) + await page.waitForFunction('!!window.$nuxt') + page.html = () => page.evaluate(() => window.document.documentElement.outerHTML) + return page +} + +// Init nuxt.js and create server listening on localhost:4003 +test.before('Init Nuxt.js', async t => { + const options = { + rootDir: resolve(__dirname, 'fixtures/basic'), + dev: false, + head: { + titleTemplate (titleChunk) { + return titleChunk ? `${titleChunk} - Nuxt.js` : 'Nuxt.js' + } + } + } + nuxt = new Nuxt(options) + await new Builder(nuxt).build() + + await nuxt.listen(port, 'localhost') +}) + +test.before('Start Puppeteer', async t => { + browser = await puppeteer.launch({ + // https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions + }) +}) + +test('/stateless', async t => { + const page = await open('/stateless') + const h1 = await page.$eval('h1', (h1) => h1.textContent) + const loading = await page.evaluate(() => window.$nuxt.$loading.$data) + + t.is(await page.title(), 'Nuxt.js') + t.is(h1, 'My component!') + t.is(loading.show, false) + t.is(loading.percent, 0) + await page.close() +}) + +test('/css', async t => { + const page = await open('/css') + t.is(await page.$eval('.red', (red) => red.textContent), 'This is red') + t.is(await page.$eval('.red', (red) => window.getComputedStyle(red).color), 'rgb(255, 0, 0)') + await page.close() +}) + +test('/stateful', async t => { + const page = await open('/stateful') + const html = await page.html() + t.true(html.includes('

The answer is 42

')) + await page.close() +}) + +// test('/store', async t => { +// const { html } = await nuxt.renderRoute('/store') +// t.true(html.includes('

Vuex Nested Modules

')) +// t.true(html.includes('

1

')) +// }) + +// test('/head', async t => { +// const window = await nuxt.renderAndGetWindow(url('/head'), { virtualConsole: false }) +// const html = window.document.body.innerHTML +// const metas = window.document.getElementsByTagName('meta') +// t.is(window.document.title, 'My title - Nuxt.js') +// t.is(metas[0].getAttribute('content'), 'my meta') +// t.true(html.includes('

I can haz meta tags

')) +// }) + +// test('/async-data', async t => { +// const { html } = await nuxt.renderRoute('/async-data') +// t.true(html.includes('

Nuxt.js

')) +// }) + +// test('/await-async-data', async t => { +// const { html } = await nuxt.renderRoute('/await-async-data') +// t.true(html.includes('

Await Nuxt.js

')) +// }) + +// test('/callback-async-data', async t => { +// const { html } = await nuxt.renderRoute('/callback-async-data') +// t.true(html.includes('

Callback Nuxt.js

')) +// }) + +// test('/users/1', async t => { +// const { html } = await nuxt.renderRoute('/users/1') +// t.true(html.includes('

User: 1

')) +// }) + +// test('/validate should display a 404', async t => { +// const { html } = await nuxt.renderRoute('/validate') +// t.true(html.includes('This page could not be found')) +// }) + +// test('/validate?valid=true', async t => { +// const { html } = await nuxt.renderRoute('/validate?valid=true') +// t.true(html.includes('

I am valid

')) +// }) + +// test('/redirect', async t => { +// const { html, redirected } = await nuxt.renderRoute('/redirect') +// t.true(html.includes('
')) +// t.true(redirected.path === '/') +// t.true(redirected.status === 302) +// }) + +// test('/redirect -> check redirected source', async t => { +// const window = await nuxt.renderAndGetWindow(url('/redirect')) +// const html = window.document.body.innerHTML +// t.true(html.includes('

Index page

')) +// }) + +// test('/special-state -> check window.__NUXT__.test = true', async t => { +// const window = await nuxt.renderAndGetWindow(url('/special-state')) +// t.is(window.document.title, 'Nuxt.js') +// t.is(window.__NUXT__.test, true) +// }) + +// test('/error', async t => { +// try { +// await nuxt.renderRoute('/error', { req: {}, res: {} }) +// } catch (err) { +// t.true(err.message.includes('Error mouahahah')) +// } +// }) + +// test('/error status code', async t => { +// try { +// await rp(url('/error')) +// } catch (err) { +// t.true(err.statusCode === 500) +// t.true(err.response.body.includes('An error occurred in the application and your page could not be served')) +// } +// }) + +// test('/error2', async t => { +// const { html, error } = await nuxt.renderRoute('/error2') +// t.true(html.includes('Custom error')) +// t.true(error.message.includes('Custom error')) +// t.true(error.statusCode === undefined) +// }) + +// test('/error2 status code', async t => { +// try { +// await rp(url('/error2')) +// } catch (err) { +// t.is(err.statusCode, 500) +// t.true(err.response.body.includes('Custom error')) +// } +// }) + +// test('/redirect2', async t => { +// stdMocks.use() +// await rp(url('/redirect2')) // Should console.error +// stdMocks.restore() +// const output = stdMocks.flush() +// // Don't display error since redirect returns a noopApp +// t.true(output.stderr.length === 0) +// }) + +// test('/no-ssr', async t => { +// const { html } = await nuxt.renderRoute('/no-ssr') +// t.true(html.includes('
<p>Loading...</p>
')) +// }) + +// test('/no-ssr (client-side)', async t => { +// const window = await nuxt.renderAndGetWindow(url('/no-ssr')) +// const html = window.document.body.innerHTML +// t.true(html.includes('Displayed only on client-side')) +// }) + +// test('ETag Header', async t => { +// const { headers: { etag } } = await rp(url('/stateless'), { resolveWithFullResponse: true }) +// // Validate etag +// t.regex(etag, /W\/".*"$/) +// // Verify functionality +// const error = await t.throws(rp(url('/stateless'), { headers: { 'If-None-Match': etag } })) +// t.is(error.statusCode, 304) +// }) + +// test('/_nuxt/server-bundle.json should return 404', async t => { +// const err = await t.throws(rp(url('/_nuxt/server-bundle.json'), { resolveWithFullResponse: true })) +// t.is(err.statusCode, 404) +// }) + +// test('/_nuxt/ should return 404', async t => { +// const err = await t.throws(rp(url('/_nuxt/'), { resolveWithFullResponse: true })) +// t.is(err.statusCode, 404) +// }) + +// Close server and ask nuxt to stop listening to file changes +test.after('Closing server and nuxt.js', t => { + nuxt.close() +}) + +test.after('Close Puppeteer', async t => { + await browser.close() + browser = null +}) diff --git a/yarn.lock b/yarn.lock index e24768274b..1ec7e417c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -101,6 +101,12 @@ acorn@^5.0.0, acorn@^5.1.1, acorn@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" +agent-base@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.1.1.tgz#92d8a4fc2524a3b09b3666a33b6c97960f23d6a4" + dependencies: + es6-promisify "^5.0.0" + ajv-keywords@^2.0.0, ajv-keywords@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.0.tgz#a296e17f7bfae7c1ce4f7e0de53d29cb32162df0" @@ -293,6 +299,10 @@ async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + async@^1.4.0: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -1669,7 +1679,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.5.0, concat-stream@^1.6.0: +concat-stream@1.6.0, concat-stream@^1.5.0, concat-stream@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -2065,7 +2075,13 @@ debug-log@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" -debug@2.6.9, debug@^2.2.0, debug@^2.6.8: +debug@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +debug@2.6.9, debug@^2.2.0, debug@^2.4.1, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2387,10 +2403,16 @@ es6-map@^0.1.3: es6-symbol "~3.1.1" event-emitter "~0.3.5" -es6-promise@^4.1.1: +es6-promise@^4.0.3, es6-promise@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.1.1.tgz#8811e90915d9a0dba36274f0b242dbda78f9c92a" +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + dependencies: + es6-promise "^4.0.3" + es6-set@~0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" @@ -2726,6 +2748,15 @@ extract-text-webpack-plugin@^3.0.2: schema-utils "^0.3.0" webpack-sources "^1.0.1" +extract-zip@^1.6.5: + version "1.6.5" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.5.tgz#99a06735b6ea20ea9b705d779acffcc87cff0440" + dependencies: + concat-stream "1.6.0" + debug "2.2.0" + mkdirp "0.5.0" + yauzl "2.4.1" + extsprintf@1.3.0, extsprintf@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -2750,6 +2781,12 @@ fastparse@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + dependencies: + pend "~1.2.0" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -3334,6 +3371,13 @@ https-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" +https-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.1.0.tgz#1391bee7fd66aeabc0df2a1fa90f58954f43e443" + dependencies: + agent-base "^4.1.0" + debug "^2.4.1" + hullabaloo-config-manager@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/hullabaloo-config-manager/-/hullabaloo-config-manager-1.1.1.tgz#1d9117813129ad035fd9e8477eaf066911269fe3" @@ -4251,6 +4295,12 @@ mississippi@^1.3.0: stream-each "^1.1.0" through2 "^2.0.0" +mkdirp@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + dependencies: + minimist "0.0.8" + "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -4268,6 +4318,10 @@ move-concurrently@^1.0.1: rimraf "^2.5.4" run-queue "^1.0.3" +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + ms@2.0.0, ms@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -4764,6 +4818,10 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" @@ -5442,6 +5500,10 @@ proxy-addr@~2.0.2: forwarded "~0.1.2" ipaddr.js "1.5.2" +proxy-from-env@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" + prr@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" @@ -5487,6 +5549,19 @@ punycode@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" +puppeteer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-0.12.0.tgz#9c421930851594dfdd479d07646666a74ced7719" + dependencies: + debug "^2.6.8" + extract-zip "^1.6.5" + https-proxy-agent "^2.1.0" + mime "^1.3.4" + progress "^2.0.0" + proxy-from-env "^1.0.0" + rimraf "^2.6.1" + ws "^3.0.0" + q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -7087,6 +7162,14 @@ ws@^2.3.1: safe-buffer "~5.0.1" ultron "~1.1.0" +ws@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.2.0.tgz#d5d3d6b11aff71e73f808f40cc69d52bb6d4a185" + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" @@ -7172,3 +7255,9 @@ yargs@~3.10.0: cliui "^2.1.0" decamelize "^1.0.0" window-size "0.1.0" + +yauzl@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + dependencies: + fd-slicer "~1.0.1"