Back to Repositories

Validating v-Slot Template Compilation for XHS Mini-Program in uni-app

This test suite examines the v-slot directive transformation in the uni-app framework for the Xiaohongshu (XHS) mini-program platform. It validates slot compilation, scoped slots handling, and compatibility with legacy slot syntax.

Test Coverage Overview

The test suite provides comprehensive coverage of slot transformation scenarios in the XHS mini-program context.

Key areas tested include:
  • Basic slot compilation and transformation
  • Named slot handling
  • Legacy slot syntax compatibility
  • Integration with XHS template syntax

Implementation Analysis

The testing approach uses Jest assertion patterns to verify correct compilation output for various slot implementations. The tests compare input Vue template syntax against expected XHS-compatible output, including proper slot attribute transformation and scope handling.

Technical implementation focuses on the assert() utility function that validates template compilation results.

Technical Details

Testing tools and configuration:
  • Jest test framework
  • Custom assert() utility for template comparison
  • TypeScript for type-safe testing
  • Template compiler transformation validation
  • XHS-specific attribute and binding syntax verification

Best Practices Demonstrated

The test suite demonstrates several testing best practices:

  • Isolated test cases for specific functionality
  • Clear input/output validation
  • Comprehensive edge case coverage
  • Platform-specific syntax verification
  • Structured test organization

dcloudio/uni-app

packages/uni-mp-xhs/__tests__/vSlot.spec.ts

            
import { assert } from './testUtils'

describe('compiler: transform v-slot', () => {
  //   test('default slot', () => {
  //     assert(
  //       `<custom><template v-slot/></custom>`,
  //       `<custom u-s="{{['d']}}" u-i="2a9ec0b0-0" bind:__l="__l"><view/></custom>`,
  //       `(_ctx, _cache) => {
  //   return {}
  // }`
  //     )
  //     assert(
  //       `<custom>test</custom>`,
  //       `<custom u-s="{{['d']}}" u-i="2a9ec0b0-0" bind:__l="__l">test</custom>`,
  //       `(_ctx, _cache) => {
  //   return {}
  // }`
  //     )
  //   })
  //   test('named slots', () => {
  //     assert(
  //       `<custom><template v-slot:header/><template v-slot:default/><template v-slot:footer/></custom>`,
  //       `<custom u-s="{{['header','d','footer']}}" u-i="2a9ec0b0-0" bind:__l="__l"><view slot="header"/><view/><view slot="footer"/></custom>`,
  //       `(_ctx, _cache) => {
  //   return {}
  // }`
  //     )
  //     assert(
  //       `<unicloud-db v-slot:default="{data, loading, error, options}"><view v-if="error">{{error.message}}</view><view v-else></view></unicloud-db>`,
  //       `<unicloud-db u-s="{{['d']}}" u-i="2a9ec0b0-0" bind:__l="__l"><view><block xhs:for="{{a}}" xhs:for-item="v0" xhs:key="c"><view xhs:if="{{v0.a}}">{{v0.b}}</view><view xhs:else></view></block></view></unicloud-db>`,
  //       `(_ctx, _cache) => {
  //   return { a: _w(({ data, loading, error, options }, s0, i0) => { return _e({ a: error }, error ? { b: _t(error.message) } : {}, { c: i0 }); }, { name: 'd', path: 'a', vueId: '2a9ec0b0-0' }) }
  // }`
  //     )
  //   })

  //   test('scoped slots', () => {
  //     assert(
  //       `<custom><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`,
  //       `<custom u-s="{{['d']}}" u-i="2a9ec0b0-0" bind:__l="__l"><view><block xhs:for="{{a}}" xhs:for-item="slotProps" xhs:key="b"><view>{{slotProps.a}}</view></block></view></custom>`,
  //       `(_ctx, _cache) => {
  //   return { a: _w((slotProps, s0, i0) => { return { a: _t(slotProps.item), b: i0 }; }, { name: 'd', path: 'a', vueId: '2a9ec0b0-0' }) }
  // }`
  //     )
  //   })

  //   test('scoped slots + scoped slots', () => {
  //     assert(
  //       `<custom><template v-slot:default="slotProps"><custom1><template v-slot:default="slotProps1">{{ slotProps.item }}{{ slotProps1.item }}</template></custom1></template></custom>`,
  //       `<custom u-s="{{['d']}}" u-i="2a9ec0b0-0" bind:__l="__l"><view><block xhs:for="{{a}}" xhs:for-item="slotProps" xhs:key="d"><custom1 u-s="{{['d']}}" u-i="{{slotProps.c}}" bind:__l="__l"><view><block xhs:for="{{slotProps.a}}" xhs:for-item="slotProps1" xhs:key="b">{{slotProps.b}}{{slotProps1.a}}</block></view></custom1></block></view></custom>`,
  //       `(_ctx, _cache) => {
  //   return { a: _w((slotProps, s0, i0) => { return { a: _w((slotProps1, s1, i1) => { return { a: _t(slotProps1.item), b: i1 }; }, { name: 'd', path: 'a[' + i0 + '].' + 'a', vueId: '2a9ec0b0-1' + '-' + i0 + ',' + '2a9ec0b0-0' }), b: _t(slotProps.item), c: '2a9ec0b0-1' + '-' + i0 + ',' + '2a9ec0b0-0', d: i0 }; }, { name: 'd', path: 'a', vueId: '2a9ec0b0-0' }) }
  // }`
  //     )
  //   })

  //   test('v-if + scoped slots', () => {
  //     assert(
  //       `<custom><template v-if="ok" v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`,
  //       `<custom u-s="{{['d']}}" u-i="2a9ec0b0-0" bind:__l="__l"><view xhs:if="{{a}}"><block xhs:for="{{b}}" xhs:for-item="slotProps" xhs:key="b"><view>{{slotProps.a}}</view></block></view></custom>`,
  //       `(_ctx, _cache) => {
  //   return _e({ a: _ctx.ok }, _ctx.ok ? { b: _w((slotProps, s0, i0) => { return { a: _t(slotProps.item), b: i0 }; }, { name: 'd', path: 'b', vueId: '2a9ec0b0-0' }) } : {})
  // }`
  //     )
  //   })

  //   test('v-for + scoped slots', () => {
  //     assert(
  //       `<custom v-for="item in items"><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`,
  //       `<custom xhs:for="{{a}}" xhs:for-item="item" u-s="{{['d']}}" u-i="{{item.b}}" bind:__l="__l"><view><block xhs:for="{{item.a}}" xhs:for-item="slotProps" xhs:key="b"><view>{{slotProps.a}}</view></block></view></custom>`,
  //       `(_ctx, _cache) => {
  //   return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _w((slotProps, s1, i1) => { return { a: _t(slotProps.item), b: i1 }; }, { name: 'd', path: 'a[' + i0 + '].' + 'a', vueId: '2a9ec0b0-0' + '-' + i0 }), b: '2a9ec0b0-0' + '-' + i0 }; }) }
  // }`
  //     )
  //   })

  //   test('v-for + v-for + scoped slots', () => {
  //     assert(
  //       `<view v-for="item in items"><custom v-for="item1 in item.list" :item="item1"><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom></view>`,
  //       `<view xhs:for="{{a}}" xhs:for-item="item"><custom xhs:for="{{item.a}}" xhs:for-item="item1" u-s="{{['d']}}" u-i="{{item1.b}}" bind:__l="__l" u-p="{{item1.c}}"><view><block xhs:for="{{item1.a}}" xhs:for-item="slotProps" xhs:key="b"><view>{{slotProps.a}}</view></block></view></custom></view>`,
  //       `(_ctx, _cache) => {
  //   return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _f(item.list, (item1, k1, i1) => { return { a: _w((slotProps, s2, i2) => { return { a: _t(slotProps.item), b: i2 }; }, { name: 'd', path: 'a[' + i0 + '].' + ('a[' + i1 + '].') + 'a', vueId: '2a9ec0b0-0' + '-' + i0 + '-' + i1 }), b: '2a9ec0b0-0' + '-' + i0 + '-' + i1, c: _p({ item: item1 }) }; }) }; }) }
  // }`
  //     )
  //   })
  test('old syntax', () => {
    assert(
      `<template slot="left"/>`,
      `<view slot="left"/>`,
      `(_ctx, _cache) => {
  return {}
}`
    )
  })
})