Back to Repositories

Testing Deep Selector Processing in CSS Scoping System in uni-app

This test suite validates the scoped CSS processing functionality in uni-app, focusing on deep selector transformations and PostCSS plugin behavior. It ensures proper handling of various deep selector syntaxes and their transformations in both removal and rewrite scenarios.

Test Coverage Overview

The test suite provides comprehensive coverage of deep selector processing in CSS.

Key areas tested include:
  • Multiple deep selector syntax variations (>>>, /deep/, ::v-deep)
  • Nested selector combinations
  • Selector transformation accuracy
  • Integration with vue-sfc-scoped plugin

Implementation Analysis

The testing approach utilizes Jest’s describe/test pattern with async/await for PostCSS processing verification. The implementation leverages PostCSS plugin architecture to process CSS transformations, with separate test cases for removal and rewriting of deep selectors.

Technical patterns include:
  • Dynamic test generation using Object.keys iteration
  • Parallel testing of removal and rewrite scenarios
  • Promise-based PostCSS processing

Technical Details

Testing infrastructure includes:
  • PostCSS for CSS processing
  • Jest as the testing framework
  • Custom stylePluginScoped PostCSS plugin
  • TypeScript for type safety
  • ProcessOptions configuration for CSS processing

Best Practices Demonstrated

The test suite exemplifies several testing best practices in the context of CSS processing.

Notable practices include:
  • Systematic test case organization
  • Comprehensive selector variation coverage
  • Clear input/output mapping
  • Isolated plugin testing
  • Type-safe implementation with TypeScript

dcloudio/uni-app

packages/uni-cli-shared/__tests__/stylePluginScoped.spec.ts

            
import postcss, { type ProcessOptions } from 'postcss'

import scopedPlugin from '../src/postcss/plugins/stylePluginScoped'

const styleCode = `{color:red;}`
const deepSelectors = [
  ['>>> a', ' a', ':deep(a)'],
  ['a >>> b', 'a b', 'a :deep(b)'],
  ['a >>> b>c', 'a b>c', 'a :deep(b>c)'],
  ['>>> a b', ' a b', ':deep(a b)'],
  ['/deep/ a', ' a', ':deep(a)'],
  ['a /deep/ b', 'a b', 'a :deep(b)'],
  ['a /deep/ b>c', 'a b>c', 'a :deep(b>c)'],
  ['/deep/ a b', ' a b', ':deep(a b)'],
  ['::v-deep a', ' a', ':deep(a)'],
  ['a ::v-deep b', 'a b', 'a :deep(b)'],
  ['a ::v-deep b>c', 'a b>c', 'a :deep(b>c)'],
  ['::v-deep a b', ' a b', ':deep(a b)'],
  ['::v-deep a b,::v-deep a', ' a b, a', ':deep(a b),:deep(a)'],
]
const removeDeepCssCodes = Object.create(null)
const rewriteDeepCssCodes = Object.create(null)
deepSelectors.forEach(([selector, removeDeepSelector, rewriteDeepSelector]) => {
  removeDeepCssCodes[selector + styleCode] = removeDeepSelector + styleCode
  rewriteDeepCssCodes[selector + styleCode] = rewriteDeepSelector + styleCode
})

const processor = postcss([scopedPlugin])

const processorWithVueSfcScoped = postcss([
  scopedPlugin,
  {
    postcssPlugin: 'vue-sfc-scoped',
  },
])

const options: ProcessOptions = { from: 'a.css', map: false }
describe('cssScoped', () => {
  Object.keys(removeDeepCssCodes).forEach((cssCode) => {
    test('remove ' + cssCode, async () => {
      return processor.process(cssCode, options).then((result) => {
        expect(result.css).toBe(removeDeepCssCodes[cssCode])
      })
    })
  })
  Object.keys(rewriteDeepCssCodes).forEach((cssCode) => {
    test('rewrite ' + cssCode, async () => {
      return processorWithVueSfcScoped
        .process(cssCode, options)
        .then((result) => {
          expect(result.css).toBe(rewriteDeepCssCodes[cssCode])
        })
    })
  })
})