`],
({ get }, reload, window, document) => {
// Find markers
let startMarker, endMarker;
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_COMMENT,
null,
false
);
let node;
while (node = walker.nextNode()) {
if (node.textContent === 'morph-start') startMarker = node;
if (node.textContent === 'morph-end') endMarker = node;
}
get('p').should(haveText('1'))
get('button').click()
get('p').should(haveText('2'))
window.Alpine.morphBetween(startMarker, endMarker, `
New element
`)
get('p').should(haveText('2'))
get('article').should(haveText('New element'))
get('input').should(haveValue('2'))
get('input').clear().type('5')
get('p').should(haveText('5'))
},
)
test('morphBetween with keyed elements',
[html`
foo
bar
`],
({ get }, reload, window, document) => {
// Find markers
let startMarker, endMarker;
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_COMMENT,
null,
false
);
let node;
while (node = walker.nextNode()) {
if (node.textContent === 'items-start') startMarker = node;
if (node.textContent === 'items-end') endMarker = node;
}
get('li:nth-of-type(1) input').type('first')
get('li:nth-of-type(2) input').type('second')
get('ul').then(([el]) => window.Alpine.morphBetween(startMarker, endMarker, `
baz
foo
bar
`, { key(el) { return el.getAttribute('key') } }))
get('li').should(haveLength(3))
get('li:nth-of-type(1)').should(haveText('baz'))
get('li:nth-of-type(2)').should(haveText('foo'))
get('li:nth-of-type(3)').should(haveText('bar'))
// Need to verify by the key attribute since the elements have been reordered
get('li[key="1"] input').should(haveValue('first'))
get('li[key="2"] input').should(haveValue('second'))
get('li[key="3"] input').should(haveValue(''))
},
)
test('morphBetween with custom key function',
[html`
Item A
Item B
`],
({ get }, reload, window, document) => {
// Find markers
let startMarker, endMarker;
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_COMMENT,
null,
false
);
let node;
while (node = walker.nextNode()) {
if (node.textContent === 'start') startMarker = node;
if (node.textContent === 'end') endMarker = node;
}
get('div[data-id="a"] input').type('aaa')
get('div[data-id="b"] input').type('bbb')
window.Alpine.morphBetween(startMarker, endMarker, `
Item B Updated
Item C
Item A Updated
`, {
key(el) { return el.dataset.id }
})
get('div[data-id]').should(haveLength(3))
get('div[data-id="b"]').should(haveText('Item B Updated'))
get('div[data-id="a"]').should(haveText('Item A Updated'))
get('div[data-id="a"] input').should(haveValue('aaa'))
get('div[data-id="b"] input').should(haveValue('bbb'))
get('div[data-id="c"] input').should(haveValue(''))
},
)
test('morphBetween with hooks',
[html`
Old paragraph
Old span
`],
({ get }, reload, window, document) => {
// Find markers
let startMarker, endMarker;
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_COMMENT,
null,
false
);
let node;
while (node = walker.nextNode()) {
if (node.textContent === 'region-start') startMarker = node;
if (node.textContent === 'region-end') endMarker = node;
}
let removedElements = []
let addedElements = []
window.Alpine.morphBetween(startMarker, endMarker, `
New paragraph
New article
`, {
removing(el) {
if (el.nodeType === 1) removedElements.push(el.tagName)
},
adding(el) {
if (el.nodeType === 1) addedElements.push(el.tagName)
}
})
get('p').should(haveText('New paragraph'))
get('article').should(haveText('New article'))
// Check hooks were called
cy.wrap(removedElements).should('deep.equal', ['SPAN'])
cy.wrap(addedElements).should('deep.equal', ['ARTICLE'])
},
)
test('morphBetween with empty content',
[html`
Title
Content 1
Content 2
End
`],
({ get }, reload, window, document) => {
// Find markers
let startMarker, endMarker;
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_COMMENT,
null,
false
);
let node;
while (node = walker.nextNode()) {
if (node.textContent === 'content-start') startMarker = node;
if (node.textContent === 'content-end') endMarker = node;
}
window.Alpine.morphBetween(startMarker, endMarker, '')
get('h3').should(haveLength(2))
get('p').should(haveLength(0))
// Verify markers are still there
let found = false;
const walker2 = document.createTreeWalker(
document.body,
NodeFilter.SHOW_COMMENT,
null,
false
);
while (node = walker2.nextNode()) {
if (node.textContent === 'content-start' || node.textContent === 'content-end') {
found = true;
}
}
cy.wrap(found).should('be.true')
},
)
test('morphBetween with nested Alpine components',
[html`
`],
({ get }, reload, window, document) => {
// Find markers
let startMarker, endMarker;
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_COMMENT,
null,
false
);
let node;
while (node = walker.nextNode()) {
if (node.textContent === 'nested-start') startMarker = node;
if (node.textContent === 'nested-end') endMarker = node;
}
get('span:nth-of-type(1)').should(haveText('foo'))
get('span:nth-of-type(2)').should(haveText('bar'))
get('input').clear().type('baz')
get('span:nth-of-type(2)').should(haveText('baz'))
window.Alpine.morphBetween(startMarker, endMarker, `
`],
({ get }, reload, window, document) => {
// Find markers
let startMarker, endMarker;
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_COMMENT,
null,
false
);
let node;
while (node = walker.nextNode()) {
if (node.textContent === 'section-start') startMarker = node;
if (node.textContent === 'section-end') endMarker = node;
}
get('div input').type('div-value')
get('p input').type('p-value')
window.Alpine.morphBetween(startMarker, endMarker, `
conditional content
new conditional
regular content
`)
get('div input').should(haveValue('div-value'))
get('span input').should(haveValue(''))
get('p input').should(haveValue('p-value'))
},
)
test('can ignore region between comment markers using skipUntil',
[html`
foo
bar
baz
`],
({ get }, reload, window, document) => {
// Generate "to" html without the items between Slot markers
let toHtml = html`
foo
`
// The original list should have 3 li's
get('li').should(haveLength(3))
get('li:nth-of-type(1)').should(haveText('foo'))
get('li:nth-of-type(2)').should(haveText('bar'))
get('li:nth-of-type(3)').should(haveText('baz'))
// Run morph with custom updating hook that calls skipUntil
let isStart = node => node && node.nodeType === 8 && node.textContent.trim() === '[Slot]'
let isEnd = node => node && node.nodeType === 8 && node.textContent.trim() === '[EndSlot]'
get('ul').then(([el]) => window.Alpine.morph(el, toHtml, {
updating(from, to, childrenOnly, skip, skipChildren, skipUntil) {
if (isStart(from) && isStart(to)) {
skipUntil(node => isEnd(node))
}
},
}))
// After morph, the list should still contain the items inside the slot
get('li').should(haveLength(3))
get('li:nth-of-type(2)').should(haveText('bar'))
get('li:nth-of-type(3)').should(haveText('baz'))
},
)