Back to Repositories

Testing CSS Combinator Parser Implementation in dcloudio/uni-app

This test suite validates the functionality of CSS combinators parsing and transformation in the uni-app nvue-styler module. It ensures accurate handling of compound selectors, descendant relationships, and other combinator types in the styling system.

Test Coverage Overview

The test suite provides comprehensive coverage of CSS combinator parsing scenarios.

Key areas tested include:
  • Compound selector combinations (.a.b)
  • Descendant selector relationships
  • Child (>), adjacent sibling (+), and general sibling (~) combinators
  • Complex nested selector patterns
  • Important declarations handling

Implementation Analysis

The testing approach utilizes Jest’s async/await pattern for handling parser operations. The implementation focuses on validating the transformation of CSS selectors into a structured JSON format, with specific attention to maintaining selector specificity and relationship hierarchies.

The tests employ a custom objectifierRule helper function that wraps the main parser functionality, providing consistent validation of both the generated code and any parsing messages.

Technical Details

Testing tools and configuration:
  • Jest as the primary testing framework
  • Custom parser utility from ‘../src’
  • JSON-based assertion patterns
  • Structured test organization with describe/test blocks
  • Async test execution for parser operations

Best Practices Demonstrated

The test suite exemplifies several testing best practices in TypeScript/Jest environments.

Notable practices include:
  • Systematic test case organization
  • Comprehensive edge case coverage
  • Clear input/output validation
  • Consistent error message checking
  • Parameterized testing for similar scenarios

dcloudio/uni-app

packages/uni-nvue-styler/__tests__/combinators.spec.ts

            
import { parse } from '../src'

async function objectifierRule(input: string) {
  const { code, messages } = await parse(input, {
    logLevel: 'NOTE',
  })
  return {
    json: JSON.parse(code),
    messages,
  }
}

describe('nvue-styler: combinators', () => {
  test('compound', async () => {
    const { json, messages } = await objectifierRule(`.a.b{left:0}`)
    expect(json).toEqual({ a: { '.b': { left: 0 } } })
    expect(messages.length).toBe(0)
    const res = await objectifierRule(`.a .b.c.d{left:0}`)
    expect(res.json).toEqual({ b: { '.a .c.d': { left: 0 } } })
    expect(res.messages.length).toBe(0)
    const res1 = await objectifierRule(
      `.a .b .c.d.e{left:0} .c{left:1} .a .c{left:2}`
    )
    expect(res1.json).toEqual({
      c: { '.a .b .d.e': { left: 0 }, '': { left: 1 }, '.a ': { left: 2 } },
    })
    expect(res1.messages.length).toBe(0)
    const res2 = await objectifierRule(`.a .b .c.d.e .f{left:0}`)
    expect(res2.json).toEqual({ f: { '.a .b .c.d.e ': { left: 0 } } })
    expect(res2.messages.length).toBe(0)
  })
  test('descendant', async () => {
    const { json, messages } = await objectifierRule(
      ` .bar {left:5!important;}.foo     .bar {left: 0!important;}.foo .bar{left:5;right:5;right:10!important}.bar .bar{left:2}.foo .bar .foobar{left:1}`
    )

    expect(json).toEqual({
      bar: {
        '': {
          '!left': 5,
        },
        '.foo ': {
          '!left': 0,
          '!right': 10,
        },
        '.bar ': {
          left: 2,
        },
      },
      foobar: { '.foo .bar ': { left: 1 } },
    })
    expect(messages.length).toBe(0)
  })
  test('other', async () => {
    const types = ['>', '+', '~']
    for (const type of types) {
      const { json, messages } = await objectifierRule(
        ` .bar {left:5;}.foo   ${type}  .bar {left: 0;}.foo${type} .bar{left:5;right:10;}.bar ${type}.bar{left:2}.foo ${type}.bar ${type}.foobar{left:1}`
      )
      expect(json).toEqual({
        bar: {
          '': {
            left: 5,
          },
          [`.foo${type}`]: {
            left: 5,
            right: 10,
          },
          [`.bar${type}`]: {
            left: 2,
          },
        },
        foobar: { [`.foo${type}.bar${type}`]: { left: 1 } },
      })
      expect(messages.length).toBe(0)
    }
  })
})