Back to Repositories

Validating CORS and Integrity Implementation in vue-cli Build Output

This test suite validates CORS (Cross-Origin Resource Sharing) and Subresource Integrity (SRI) functionality in Vue CLI build output. It verifies the correct implementation of crossorigin attributes and integrity hashes in the generated HTML, CSS, and JavaScript files.

Test Coverage Overview

The test suite provides comprehensive coverage of build output validation for CORS and SRI implementations.

Key areas tested include:
  • HTML output verification for crossorigin attributes
  • Integrity hash generation and validation for JS and CSS files
  • Runtime verification of built assets
  • Module script loading with proper CORS attributes

Implementation Analysis

The testing approach uses Jest combined with Puppeteer for end-to-end validation. It creates a test project with custom Vue configuration, builds it, and verifies the output through both static analysis and runtime execution.

Notable patterns include:
  • Project creation with default preset
  • Custom vue.config.js configuration
  • Static HTML parsing and regex matching
  • Dynamic server creation for runtime testing

Technical Details

Testing tools and configuration:
  • Jest as the test runner
  • Puppeteer for browser automation
  • portfinder for dynamic port allocation
  • @vue/cli-test-utils for project creation and server setup
  • Custom server implementation for serving built assets
  • 30-second timeout configuration

Best Practices Demonstrated

The test implementation showcases several testing best practices for build output validation.

Notable practices include:
  • Proper test cleanup with afterAll hooks
  • Async/await pattern usage
  • Resource management for browser and server instances
  • Comprehensive assertion coverage
  • Both static and runtime verification approaches

vuejs/vue-cli

packages/@vue/cli-service/__tests__/cors.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-cors', defaultPreset)

  await project.write('vue.config.js', `
    module.exports = {
      crossorigin: '',
      integrity: true
    }
  `)

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

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

  // preload disabled due to chrome bug
  // https://bugs.chromium.org/p/chromium/issues/detail?id=677022
  // expect(index).toMatch(/<link [^>]+js\/app[^>]+\.js rel=preload as=script crossorigin>/)
  // expect(index).toMatch(/<link [^>]+js\/chunk-vendors[^>]+\.js rel=preload as=script crossorigin>/)
  // expect(index).toMatch(/<link [^>]+app[^>]+\.css rel=preload as=style crossorigin>/)

  // should apply crossorigin and add integrity to scripts and css
  expect(index).toMatch(/<script defer="defer" type="module" src="\/js\/chunk-vendors\.\w{8}\.js" crossorigin integrity="sha384-.{64}\s?">/)
  expect(index).toMatch(/<script defer="defer" type="module" src="\/js\/app\.\w{8}\.js" crossorigin integrity="sha384-.{64}\s?">/)
  expect(index).toMatch(/<link href="\/css\/app\.\w{8}\.css" rel="stylesheet" crossorigin integrity="sha384-.{64}\s?">/)

  // verify integrity is correct by actually running it
  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')
})

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