x-if.spec.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { exist, haveText, html, notExist, test } from '../../utils'
  2. test('x-if',
  3. html`
  4. <div x-data="{ show: false }">
  5. <button @click="show = ! show">Toggle</button>
  6. <template x-if="show">
  7. <h1>Toggle Me</h1>
  8. </template>
  9. </div>
  10. `,
  11. ({ get }) => {
  12. get('h1').should(notExist())
  13. get('button').click()
  14. get('h1').should(exist())
  15. get('button').click()
  16. get('h1').should(notExist())
  17. }
  18. )
  19. test('x-if inside x-for allows nested directives',
  20. html`
  21. <div x-data="{items: [{id: 1, label: '1'}]}">
  22. <template x-for="item in items" :key="item.id">
  23. <div>
  24. <template x-if="item.label">
  25. <span x-text="item.label"></span>
  26. </template>
  27. </div>
  28. </template>
  29. </div>
  30. `,
  31. ({ get }) => {
  32. get('span').should(haveText('1'))
  33. }
  34. )
  35. test('x-if initializes after being added to the DOM to allow x-ref to work',
  36. html`
  37. <div x-data="{}">
  38. <template x-if="true">
  39. <ul x-ref="listbox" data-foo="bar">
  40. <li x-text="$refs.listbox.dataset.foo"></li>
  41. </ul>
  42. </template>
  43. </div>
  44. `,
  45. ({ get }) => {
  46. get('li').should(haveText('bar'))
  47. }
  48. )
  49. // If x-if evaluates to false, the expectation is that no sub-expressions will be evaluated.
  50. test('x-if removed dom does not evaluate reactive expressions in dom tree',
  51. html`
  52. <div x-data="{user: {name: 'lebowski'}}">
  53. <button @click="user = null">Log out</button>
  54. <template x-if="user">
  55. <span x-text="user.name"></span>
  56. </template>
  57. </div>
  58. `,
  59. ({ get }) => {
  60. get('span').should(haveText('lebowski'))
  61. // Clicking button sets user=null and thus x-if="user" will evaluate to false.
  62. // If the sub-expression x-text="user.name" is evaluated, the button click
  63. // will produce an error because user is no longer defined and the test will fail
  64. get('button').click()
  65. get('span').should(notExist())
  66. }
  67. )
  68. // Attempting to skip an already-flushed reactive effect would cause inconsistencies when updating other effects.
  69. // See https://github.com/alpinejs/alpine/issues/2803 for more details.
  70. test('x-if removed dom does not attempt skipping already-processed reactive effects in dom tree',
  71. html`
  72. <div x-data="{
  73. isEditing: true,
  74. foo: 'random text',
  75. stopEditing() {
  76. this.foo = '';
  77. this.isEditing = false;
  78. },
  79. }">
  80. <button @click="stopEditing">Stop editing</button>
  81. <template x-if="isEditing">
  82. <div id="div-editing">
  83. <h2>Editing</h2>
  84. <input id="foo" name="foo" type="text" x-model="foo" />
  85. </div>
  86. </template>
  87. <template x-if="!isEditing">
  88. <div id="div-not-editing"><h2>Not editing</h2></div>
  89. </template>
  90. <template x-if="!isEditing">
  91. <div id="div-also-not-editing"><h2>Also not editing</h2></div>
  92. </template>
  93. </div>
  94. `,
  95. ({ get }) => {
  96. get('button').click()
  97. get('div#div-editing').should(notExist())
  98. get('div#div-not-editing').should(exist())
  99. get('div#div-also-not-editing').should(exist())
  100. }
  101. )