Back to Repositories

Testing Vue CLI Build Process Implementation in vuejs/vue-cli

This test suite validates the build functionality of Vue CLI, focusing on the build process, output verification, and configuration options. It ensures proper asset generation, file handling, and build reporting capabilities.

Test Coverage Overview

The test suite provides comprehensive coverage of Vue CLI’s build process.

Key areas tested include:
  • Basic build output verification
  • Public asset copying and handling
  • HTML template generation and injection
  • Build reporting functionality
  • Custom destination directory support

Implementation Analysis

The testing approach utilizes Jest for running end-to-end build tests. It implements project creation, file manipulation, and build output verification patterns. The tests leverage Puppeteer for browser-based validation and custom utility functions for project management.

Framework-specific features tested include asset preloading, script injection, and Vue.js template processing.

Technical Details

Testing tools and setup:
  • Jest as the test runner
  • Puppeteer for browser automation
  • portfinder for dynamic port allocation
  • Custom Vue CLI test utilities
  • File system operations for output verification

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices through comprehensive build output validation, proper test isolation, and thorough error checking. Notable practices include:
  • Automated cleanup with afterAll hooks
  • Dynamic port handling for server tests
  • Detailed asset and file verification
  • Structured test organization

vuejs/vue-cli

packages/@vue/cli-service/__tests__/build.spec.js

            
jest.setTimeout(30000)

const path = require('path')
const portfinder = require('portfinder')
const createServer = require('@vue/cli-test-utils/createServer')
const { defaultPreset } = require('@vue/cli/lib/options')
const create = require('@vue/cli-test-utils/createTestProject')
const launchPuppeteer = require('@vue/cli-test-utils/launchPuppeteer')

let server, browser, page
test('build', async () => {
  const project = await create('e2e-build', defaultPreset)

  // test public copy
  project.write('public/foo.js', '1')
  // make sure that only /public/index.html is skipped (#3119)
  project.write('public/subfolder/index.html', '1')

  const { stdout } = await project.run('vue-cli-service build')
  expect(stdout).toMatch('Build complete.')

  expect(project.has('dist/index.html')).toBe(true)
  expect(project.has('dist/favicon.ico')).toBe(true)
  expect(project.has('dist/js')).toBe(true)
  expect(project.has('dist/css')).toBe(true)
  expect(project.has('dist/foo.js')).toBe(true)
  expect(project.has('dist/subfolder/index.html')).toBe(true)

  const index = await project.read('dist/index.html')

  // should have set the title inferred from the project name
  expect(index).toMatch(/<title>e2e-build<\/title>/)

  // should split and preload app.js & vendor.js
  // expect(index).toMatch(/<link [^>]+js\/app[^>]+\.js" rel="preload" as="script">/)
  // expect(index).toMatch(/<link [^>]+js\/chunk-vendors[^>]+\.js" rel="preload" as="script">/)
  // should preload css
  // expect(index).toMatch(/<link [^>]+app[^>]+\.css" rel="preload" as="style">/)

  // should inject scripts
  expect(index).toMatch(/<script defer="defer" src="\/js\/chunk-vendors-legacy\.\w{8}\.js" nomodule>/)
  expect(index).toMatch(/<script defer="defer" src="\/js\/app-legacy\.\w{8}\.js" nomodule>/)
  // should inject css
  expect(index).toMatch(/<link href="\/css\/app\.\w{8}\.css" rel="stylesheet">/)

  // should reference favicon with correct base URL
  expect(index).toMatch(/<link rel="icon" href="\/favicon.ico">/)

  const port = await portfinder.getPortPromise()
  server = createServer({ root: path.join(project.dir, 'dist') })

  await new Promise((resolve, reject) => {
    server.listen(port, err => {
      if (err) return reject(err)
      resolve()
    })
  })

  const launched = await launchPuppeteer(`http://localhost:${port}/`)
  browser = launched.browser
  page = launched.page

  const h1Text = await page.evaluate(() => {
    return document.querySelector('h1').textContent
  })

  expect(h1Text).toMatch('Welcome to Your Vue.js App')
})

test('build with --report-json', async () => {
  const project = await create('e2e-build-report-json', defaultPreset)

  const { stdout } = await project.run('vue-cli-service build --report-json')
  expect(stdout).toMatch('Build complete.')
  // should generate report.json
  expect(project.has('dist/report.json')).toBe(true)

  const report = JSON.parse(await project.read('dist/report.json'))
  // should contain entry points info
  expect(report.entrypoints).toHaveProperty('app.chunks')
  expect(report.entrypoints).toHaveProperty('app.assets')

  const appChunk = report.chunks.find(chunk => chunk.names.includes('app'))
  // Each chunk should contain meta info
  expect(appChunk).toHaveProperty('rendered')
  expect(appChunk).toHaveProperty('initial')
  expect(appChunk).toHaveProperty('entry')
  expect(appChunk).toHaveProperty('size')
  expect(appChunk).toHaveProperty('names')
  expect(appChunk).toHaveProperty('files')
  expect(appChunk).toHaveProperty('modules')
})

test('build with --dest', async () => {
  const project = await create('e2e-build-dest', defaultPreset)

  const { stdout } = await project.run('vue-cli-service build --dest other_dist')
  expect(stdout).toMatch('Build complete.')

  expect(project.has('other_dist/index.html')).toBe(true)
  expect(project.has('other_dist/favicon.ico')).toBe(true)
  expect(project.has('other_dist/js')).toBe(true)
  expect(project.has('other_dist/css')).toBe(true)

  expect(project.has('dist')).toBe(false)
})

afterAll(async () => {
  if (browser) {
    await browser.close()
  }
  if (server) {
    server.close()
  }
})