diff --git a/test/fixtures/ssr/components/test.vue b/test/fixtures/ssr/components/test.vue
new file mode 100644
index 0000000000..cdc10f9b6f
--- /dev/null
+++ b/test/fixtures/ssr/components/test.vue
@@ -0,0 +1,17 @@
+
+
+ {{id}}
+
+
+
+
\ No newline at end of file
diff --git a/test/fixtures/ssr/lib/db.js b/test/fixtures/ssr/lib/db.js
new file mode 100644
index 0000000000..9c173807f6
--- /dev/null
+++ b/test/fixtures/ssr/lib/db.js
@@ -0,0 +1,4 @@
+
+let idCtr = 0
+
+export const nextId = () => ++idCtr
diff --git a/test/fixtures/ssr/pages/asyncData.vue b/test/fixtures/ssr/pages/asyncData.vue
new file mode 100644
index 0000000000..5f194666ed
--- /dev/null
+++ b/test/fixtures/ssr/pages/asyncData.vue
@@ -0,0 +1,15 @@
+
+{{id}}
+
+
+
diff --git a/test/fixtures/ssr/pages/component.vue b/test/fixtures/ssr/pages/component.vue
new file mode 100644
index 0000000000..316ad6e5ec
--- /dev/null
+++ b/test/fixtures/ssr/pages/component.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/fixtures/ssr/pages/data.vue b/test/fixtures/ssr/pages/data.vue
new file mode 100644
index 0000000000..f627b7b373
--- /dev/null
+++ b/test/fixtures/ssr/pages/data.vue
@@ -0,0 +1,15 @@
+
+{{id}}
+
+
+
diff --git a/test/fixtures/ssr/pages/fetch.vue b/test/fixtures/ssr/pages/fetch.vue
new file mode 100644
index 0000000000..27ed0ec8bc
--- /dev/null
+++ b/test/fixtures/ssr/pages/fetch.vue
@@ -0,0 +1,14 @@
+
+{{$store.__id}}
+
+
+
diff --git a/test/fixtures/ssr/pages/store.vue b/test/fixtures/ssr/pages/store.vue
new file mode 100644
index 0000000000..767e0f3b23
--- /dev/null
+++ b/test/fixtures/ssr/pages/store.vue
@@ -0,0 +1,5 @@
+
+
+ {{$store.state[$route.query.onServerInit === '1' ? 'id2': 'id']}}
+
+
\ No newline at end of file
diff --git a/test/fixtures/ssr/store/index.js b/test/fixtures/ssr/store/index.js
new file mode 100644
index 0000000000..e98ccc4f5d
--- /dev/null
+++ b/test/fixtures/ssr/store/index.js
@@ -0,0 +1,22 @@
+import { nextId } from '@/lib/db'
+
+export const state = () => {
+ return {
+ id: nextId(),
+ id2: 0
+ }
+}
+
+export const mutations = {
+ setId2 (state, id) {
+ state.id2 = id
+ }
+}
+
+export const actions = {
+ nuxtServerInit ({ commit, state }, { route }) {
+ if (route.query.onServerInit === '1') {
+ commit('setId2', nextId())
+ }
+ }
+}
diff --git a/test/ssr.test.js b/test/ssr.test.js
new file mode 100755
index 0000000000..09a3bc0aa7
--- /dev/null
+++ b/test/ssr.test.js
@@ -0,0 +1,84 @@
+import test from 'ava'
+import { resolve } from 'path'
+import { Nuxt, Builder, Utils } from '..'
+import { uniq } from 'lodash'
+
+const port = 4008
+let nuxt = null
+
+// Utils
+const range = n => [...Array(n).keys()]
+const FOOBAR_REGEX = /([\s\S]*)<\/foobar>/
+const match = (regex, text) => (regex.exec(text) || [])[1]
+
+// Init nuxt.js and create server listening on localhost:4000
+test.before('Init Nuxt.js', async t => {
+ const options = {
+ rootDir: resolve(__dirname, 'fixtures/ssr'),
+ dev: false,
+ render: {
+ resourceHints: false
+ },
+ build: {
+ extractCSS: true
+ }
+ }
+ nuxt = new Nuxt(options)
+ await new Builder(nuxt).build()
+ await nuxt.listen(port, 'localhost')
+})
+
+// == Uniq Test ==
+// The idea behind is pages using a shared nextId() which retuns an increamenting id
+// So all responses should strictly be different and length of unique responses should equal to responses
+// We strictly compare {id} section
+// Because other response parts such as window.__NUXT may be different resulting false positive passes.
+const uniqueTest = async (t, url) => {
+ let results = []
+
+ await Utils.parallel(range(20), async () => {
+ let { html } = await nuxt.renderRoute(url)
+ let foobar = match(FOOBAR_REGEX, html)
+ results.push(parseInt(foobar))
+ })
+
+ let isUnique = uniq(results).length === results.length
+
+ if (!isUnique) {
+ /* eslint-disable no-console */
+ console.log(url + '\n' + results.join(', ') + '\n')
+ }
+
+ t.true(isUnique)
+
+ return results
+}
+
+test('unique responses with data()', async t => {
+ await uniqueTest(t, '/data')
+})
+
+test('unique responses with component', async t => {
+ await uniqueTest(t, '/component')
+})
+
+test('unique responses with asyncData()', async t => {
+ await uniqueTest(t, '/asyncData')
+})
+
+test('unique responses with store initial state', async t => {
+ await uniqueTest(t, '/store')
+})
+
+test('unique responses with nuxtServerInit', async t => {
+ await uniqueTest(t, '/store?onServerInit=1')
+})
+
+test('unique responses with fetch', async t => {
+ await uniqueTest(t, '/fetch')
+})
+
+// Close server and ask nuxt to stop listening to file changes
+test.after('Closing server and nuxt.js', t => {
+ nuxt.close()
+})