Back to Repositories

Testing v-Model Directive Transformation in uni-app Compiler

This test suite examines the v-model directive transformation in the uni-app compiler, focusing on component and input element bindings. It verifies the proper compilation of two-way data binding across different scenarios including modifiers like trim and number.

Test Coverage Overview

The test suite provides comprehensive coverage of v-model implementations across components and form elements:

  • Basic component v-model bindings
  • Input and textarea element bindings
  • Handler caching scenarios
  • Modifier combinations (.number, .trim)
  • Event handling integration

Implementation Analysis

The testing approach uses assertion-based verification to compare input templates against expected compiled output. It employs Jest’s describe/test structure with custom assert utilities to validate both the generated template markup and corresponding render functions.

The tests specifically verify the transformation of v-model directives into platform-specific bindings (u-p, bindupdateModelValue) and event handlers.

Technical Details

Testing Framework:
  • Jest as the primary test runner
  • Custom assert utility for template transformation validation
  • Template compiler transformation verification
  • Runtime binding analysis

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Isolated test cases for each v-model variation
  • Explicit expected outputs for both markup and render functions
  • Comprehensive modifier combination testing
  • Clear test case organization and naming
  • Validation of both simple and complex scenarios

dcloudio/uni-app

packages/uni-mp-compiler/__tests__/vModel.spec.ts

            
import { assert } from './testUtils'

describe('compiler: transform v-model', () => {
  test(`component v-model`, () => {
    assert(
      `<Comp v-model="model" />`,
      `<comp u-i="2a9ec0b0-0" bindupdateModelValue="{{a}}" u-p="{{b||''}}"/>`,
      `(_ctx, _cache) => {
  return { a: _o($event => _ctx.model = $event), b: _p({ modelValue: _ctx.model }) }
}`
    )
  })
  test(`component v-model with cache`, () => {
    assert(
      `<Comp v-model="model" />`,
      `<comp u-i="2a9ec0b0-0" bindupdateModelValue="{{a}}" u-p="{{b||''}}"/>`,
      `(_ctx, _cache) => {
  return { a: _o($event => _ctx.model = $event), b: _p({ modelValue: _ctx.model }) }
}`,
      {
        cacheHandlers: true,
      }
    )
  })
  test(`component v-model with number`, () => {
    assert(
      `<Comp v-model.number="model" />`,
      `<comp u-i="2a9ec0b0-0" bindupdateModelValue="{{a}}" u-p="{{b||''}}"/>`,
      `(_ctx, _cache) => {
  return { a: _o(_m($event => _ctx.model = $event, { number: true }, true)), b: _p({ modelValue: _ctx.model }) }
}`,
      {
        cacheHandlers: true,
      }
    )
  })
  test(`component v-model with trim`, () => {
    assert(
      `<Comp v-model.trim="model" />`,
      `<comp u-i="2a9ec0b0-0" bindupdateModelValue="{{a}}" u-p="{{b||''}}"/>`,
      `(_ctx, _cache) => {
  return { a: _o(_m($event => _ctx.model = $event, { trim: true }, true)), b: _p({ modelValue: _ctx.model }) }
}`,
      {
        cacheHandlers: true,
      }
    )
  })
  test(`component v-model with number and trim`, () => {
    assert(
      `<Comp v-model.trim.number="model" />`,
      `<comp u-i="2a9ec0b0-0" bindupdateModelValue="{{a}}" u-p="{{b||''}}"/>`,
      `(_ctx, _cache) => {
  return { a: _o(_m($event => _ctx.model = $event, { trim: true, number: true }, true)), b: _p({ modelValue: _ctx.model }) }
}`
    )
  })
  test(`input,textarea v-model`, () => {
    assert(
      `<input v-model="model" />`,
      `<input value="{{a}}" bindinput="{{b}}"/>`,
      `(_ctx, _cache) => {
  return { a: _ctx.model, b: _o($event => _ctx.model = $event.detail.value) }
}`
    )
    assert(
      `<textarea v-model="model" />`,
      `<textarea value="{{a}}" bindinput="{{b}}"/>`,
      `(_ctx, _cache) => {
  return { a: _ctx.model, b: _o($event => _ctx.model = $event.detail.value) }
}`
    )
  })
  test(`input v-model + v-on`, () => {
    assert(
      `<input @input="input" v-model="model" />`,
      `<input bindinput="{{a}}" value="{{b}}"/>`,
      `(_ctx, _cache) => {
  return { a: _o([$event => _ctx.model = $event.detail.value, _ctx.input]), b: _ctx.model }
}`
    )
  })
  test(`input v-model with number`, () => {
    assert(
      `<input v-model.number="model" />`,
      `<input value="{{a}}" bindinput="{{b}}"/>`,
      `(_ctx, _cache) => {
  return { a: _ctx.model, b: _o(_m($event => _ctx.model = $event.detail.value, { number: true })) }
}`
    )
  })
  test(`input v-model with number and trim`, () => {
    assert(
      `<input v-model.trim.number="model" />`,
      `<input value="{{a}}" bindinput="{{b}}"/>`,
      `(_ctx, _cache) => {
  return { a: _ctx.model, b: _o(_m($event => _ctx.model = $event.detail.value, { trim: true, number: true })) }
}`
    )
  })
  test(`input v-model.number + v-on`, () => {
    assert(
      `<input @input="input" v-model.number="model" />`,
      `<input bindinput="{{a}}" value="{{b}}"/>`,
      `(_ctx, _cache) => {
  return { a: _o([_m($event => _ctx.model = $event.detail.value, { number: true }), _ctx.input]), b: _ctx.model }
}`
    )
  })
})