Back to Repositories

Testing Plugin Dependency Sorting Implementation in Vue CLI

This test suite validates the topological sorting functionality for Vue CLI plugins, ensuring correct dependency ordering and cycle detection. It verifies the plugin execution order based on ‘after’ dependencies while handling both simple and complex dependency scenarios.

Test Coverage Overview

The test suite provides comprehensive coverage of plugin ordering scenarios.

Key areas tested include:
  • Default ordering preservation without dependencies
  • Single dependency chain resolution
  • Multiple dependency handling with array syntax
  • Cyclic dependency detection and error handling

Implementation Analysis

The testing approach uses Jest’s describe/test pattern to organize related test cases systematically. Each test case creates mock plugin configurations using a helper function that simulates Vue CLI plugin structure with ‘after’ dependencies. The implementation leverages Jest’s expect assertions to verify correct sorting outcomes.

Technical patterns include:
  • Plugin factory function for consistent test data creation
  • Dependency specification using string and array formats
  • Warning log verification for error conditions

Technical Details

Testing infrastructure includes:
  • Jest as the testing framework
  • Custom plugin helper function for test data generation
  • Mock logger implementation for warning verification
  • Topological sorting algorithm from cli-shared-utils

Best Practices Demonstrated

The test suite exemplifies several testing best practices including isolation of test cases, comprehensive edge case coverage, and clear test organization. Notable practices include:
  • Descriptive test case naming
  • Isolated test scenarios
  • Error condition handling
  • Consistent test data structure
  • Modular test helper functions

vuejs/vue-cli

packages/@vue/cli-shared-utils/__tests__/pluginOrder.spec.js

            
const { topologicalSorting } = require('../lib/pluginOrder')
const { logs } = require('../lib/logger')

/**
 *
 * @param {string} id
 * @param {{stage: number, after: string|Array<string>}} [order]
 */
function plugin (id, order) {
  order = order || {}
  const { after } = order

  // use object instead of function here
  const apply = {}
  apply.after = after
  return {
    id,
    apply
  }
}

describe('topologicalSorting', () => {
  test(`no specifying 'after' will preserve sort order`, () => {
    const plugins = [
      plugin('foo'),
      plugin('bar'),
      plugin('baz')
    ]
    const orderPlugins = topologicalSorting(plugins)
    expect(orderPlugins).toEqual(plugins)
  })

  test(`'after' specified`, () => {
    const plugins = [
      plugin('foo', { after: 'bar' }),
      plugin('bar', { after: 'baz' }),
      plugin('baz')
    ]
    const orderPlugins = topologicalSorting(plugins)
    expect(orderPlugins).toEqual([
      plugin('baz'),
      plugin('bar', { after: 'baz' }),
      plugin('foo', { after: 'bar' })
    ])
  })

  test(`'after' can be Array<string>`, () => {
    const plugins = [
      plugin('foo', { after: ['bar', 'baz'] }),
      plugin('bar'),
      plugin('baz')
    ]
    const orderPlugins = topologicalSorting(plugins)
    expect(orderPlugins).toEqual([
      plugin('bar'),
      plugin('baz'),
      plugin('foo', { after: ['bar', 'baz'] })
    ])
  })

  test('it is not possible to sort plugins because of cyclic graph, return original plugins directly', () => {
    logs.warn = []
    const plugins = [
      plugin('foo', { after: 'bar' }),
      plugin('bar', { after: 'baz' }),
      plugin('baz', { after: 'foo' })
    ]
    const orderPlugins = topologicalSorting(plugins)
    expect(orderPlugins).toEqual(plugins)

    expect(logs.warn.length).toBe(1)
  })
})