/* global jasmine, describe, it, expect, beforeAll, afterAll */

import { join } from 'path'
import getPort from 'get-port'
import clone from 'clone'
import cheerio from 'cheerio'
import {
  initNextServerScript,
  killApp,
  renderViaHTTP,
  fetchViaHTTP
} from 'next-test-utils'
import webdriver from 'next-webdriver'

const appDir = join(__dirname, '../')
let appPort
let server
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 2

const context = {}

const startServer = async (optEnv = {}) => {
  const scriptPath = join(appDir, 'server.js')
  context.appPort = appPort = await getPort()
  const env = Object.assign(
    {},
    clone(process.env),
    { PORT: `${appPort}` },
    optEnv
  )

  server = await initNextServerScript(scriptPath, /Ready on/, env)
}

describe('Custom Server', () => {
  describe('with dynamic assetPrefix', () => {
    beforeAll(() => startServer())
    afterAll(() => killApp(server))

    it('should set the assetPrefix dynamically', async () => {
      const normalUsage = await renderViaHTTP(appPort, '/asset')
      expect(normalUsage).not.toMatch(/127\.0\.0\.1/)

      const dynamicUsage = await renderViaHTTP(appPort, '/asset?setAssetPrefix=1')
      expect(dynamicUsage).toMatch(/127\.0\.0\.1/)
    })

    it('should handle null assetPrefix accordingly', async () => {
      const $normal = cheerio.load(await renderViaHTTP(appPort, '/asset?setEmptyAssetPrefix=1'))
      expect($normal('img').attr('src')).toBe('/static/myimage.png')
    })

    it('should set the assetPrefix to a given request', async () => {
      for (let lc = 0; lc < 1000; lc++) {
        const [normalUsage, dynamicUsage] = await Promise.all([
          await renderViaHTTP(appPort, '/asset'),
          await renderViaHTTP(appPort, '/asset?setAssetPrefix=1')
        ])

        expect(normalUsage).not.toMatch(/127\.0\.0\.1/)
        expect(dynamicUsage).toMatch(/127\.0\.0\.1/)
      }
    })

    it('should support next/asset in server side', async () => {
      const $normal = cheerio.load(await renderViaHTTP(appPort, '/asset'))
      expect($normal('img').attr('src')).toBe('/static/myimage.png')

      const $dynamic = cheerio.load(await renderViaHTTP(appPort, '/asset?setAssetPrefix=1'))
      expect($dynamic('img').attr('src')).toBe(`http://127.0.0.1:${context.appPort}/static/myimage.png`)
    })

    it('should support next/asset in client side', async () => {
      const browser = await webdriver(context.appPort, '/')
      await browser
        .elementByCss('#go-asset').click()
        .waitForElementByCss('#asset-page')

      expect(await browser.elementByCss('img').getAttribute('src'))
        .toBe(`http://localhost:${context.appPort}/static/myimage.png`)
      browser.close()

      const browser2 = await webdriver(context.appPort, '/?setAssetPrefix=1')
      await browser2
        .elementByCss('#go-asset').click()
        .waitForElementByCss('#asset-page')

      expect(await browser2.elementByCss('img').getAttribute('src'))
        .toBe(`http://127.0.0.1:${context.appPort}/static/myimage.png`)
      browser2.close()
    })
  })

  describe('with generateEtags enabled', () => {
    beforeAll(() => startServer({ GENERATE_ETAGS: 'true' }))
    afterAll(() => killApp(server))

    it('response includes etag header', async () => {
      const response = await fetchViaHTTP(appPort, '/')
      expect(response.headers.get('etag')).toBeTruthy()
    })
  })

  describe('with generateEtags disabled', () => {
    beforeAll(() => startServer({ GENERATE_ETAGS: 'false' }))
    afterAll(() => killApp(server))

    it('response does not include etag header', async () => {
      const response = await fetchViaHTTP(appPort, '/')
      expect(response.headers.get('etag')).toBeNull()
    })
  })
})
