import Alpine from 'alpinejs' import { wait, fireEvent } from '@testing-library/dom' const timeout = ms => new Promise(resolve => setTimeout(resolve, ms)) global.MutationObserver = class { observe() {} } test('data modified in event listener updates affected attribute bindings', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').getAttribute('foo')).toEqual('bar') document.querySelector('button').click() await wait(() => { expect(document.querySelector('span').getAttribute('foo')).toEqual('baz') }) }) test('nested data modified in event listener updates affected attribute bindings', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').getAttribute('foo')).toEqual('bar') document.querySelector('button').click() await wait(() => { expect(document.querySelector('span').getAttribute('foo')).toEqual('baz') }) }) test('.passive modifier should disable e.preventDefault()', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('div').__x.$data.defaultPrevented).toEqual(null) fireEvent.mouseDown(document.querySelector('button')) await wait(() => { expect(document.querySelector('div').__x.$data.defaultPrevented).toEqual(false) }) }) test('.stop modifier', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('div').__x.$data.foo).toEqual('bar') document.querySelector('span').click() await wait(() => { expect(document.querySelector('div').__x.$data.foo).toEqual('baz') }) }) test('.self modifier', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').textContent).toEqual('bar') document.querySelector('button').click() await wait(() => { expect(document.querySelector('span').textContent).toEqual('bar') }) document.querySelector('#selfTarget').click() await wait(() => { expect(document.querySelector('span').textContent).toEqual('baz') }) }) test('.prevent modifier', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('input').checked).toEqual(false) document.querySelector('input').click() expect(document.querySelector('input').checked).toEqual(false) }) test('.window modifier', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').getAttribute('foo')).toEqual('bar') document.body.click() await wait(() => { expect(document.querySelector('span').getAttribute('foo')).toEqual('baz') }) }) test('unbind global event handler when element is removed', async () => { document._callCount = 0 document.body.innerHTML = `
` Alpine.start() document.body.click() document.body.innerHTML = '' document.body.click() await new Promise(resolve => setTimeout(resolve, 1)) expect(document._callCount).toEqual(1) }) test('.document modifier', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').getAttribute('foo')).toEqual('bar') document.body.click() await wait(() => { expect(document.querySelector('span').getAttribute('foo')).toEqual('baz') }) }) test('.once modifier', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').getAttribute('foo')).toEqual('0') document.querySelector('button').click() await wait(() => { expect(document.querySelector('span').getAttribute('foo')).toEqual('1') }) document.querySelector('button').click() await timeout(25) expect(document.querySelector('span').getAttribute('foo')).toEqual('1') }) test('.once modifier does not remove listener if false is returned', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').getAttribute('foo')).toEqual('0') document.querySelector('button').click() await wait(() => { expect(document.querySelector('span').getAttribute('foo')).toEqual('1') }) document.querySelector('button').click() await wait(() => { expect(document.querySelector('span').getAttribute('foo')).toEqual('2') }) await timeout(25) expect(document.querySelector('span').getAttribute('foo')).toEqual('2') }) test('keydown modifiers', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').textContent).toEqual('0') fireEvent.keyDown(document.querySelector('input'), { key: 'Enter' }) await wait(() => { expect(document.querySelector('span').textContent).toEqual('2') }) fireEvent.keyDown(document.querySelector('input'), { key: ' ' }) await wait(() => { expect(document.querySelector('span').textContent).toEqual('4') }) fireEvent.keyDown(document.querySelector('input'), { key: 'Spacebar' }) await wait(() => { expect(document.querySelector('span').textContent).toEqual('6') }) fireEvent.keyDown(document.querySelector('input'), { key: 'Escape' }) await wait(() => { expect(document.querySelector('span').textContent).toEqual('7') }) }) test('keydown combo modifiers', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').textContent).toEqual('0') fireEvent.keyDown(document.querySelector('input'), { key: 'Enter' }) await wait(() => { expect(document.querySelector('span').textContent).toEqual('0') }) fireEvent.keyDown(document.querySelector('input'), { key: 'Enter', metaKey: true }) await wait(() => { expect(document.querySelector('span').textContent).toEqual('1') }) }) test('keydown with specified key and stop modifier only stops for specified key', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').textContent).toEqual('0') fireEvent.keyDown(document.querySelector('input'), { key: 'Escape' }) await wait(() => { expect(document.querySelector('span').textContent).toEqual('1') }) fireEvent.keyDown(document.querySelector('input'), { key: 'Enter' }) await timeout(25) expect(document.querySelector('span').textContent).toEqual('1') }) test('click away', async () => { // Because jsDom doesn't support .offsetHeight and offsetWidth, we have to // make our own implementation using a specific class added to the class. Ugh. Object.defineProperties(window.HTMLElement.prototype, { offsetHeight: { get: function () { return this.classList.contains('hidden') ? 0 : 1 } }, offsetWidth: { get: function () { return this.classList.contains('hidden') ? 0 : 1 } } }); document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('ul').classList.contains('hidden')).toEqual(false) document.querySelector('li').click() await wait(() => { expect(document.querySelector('ul').classList.contains('hidden')).toEqual(false) }) document.querySelector('ul').click() await wait(() => { expect(document.querySelector('ul').classList.contains('hidden')).toEqual(false) }) document.querySelector('#outer').click() await wait(() => { expect(document.querySelector('ul').classList.contains('hidden')).toEqual(true) }) document.querySelector('button').click() await wait(() => { expect(document.querySelector('ul').classList.contains('hidden')).toEqual(false) }) }) test('.passive + .away modifier still disables e.preventDefault()', async () => { // Pretend like all the elements are visible Object.defineProperties(window.HTMLElement.prototype, { offsetHeight: { get: () => 1 }, offsetWidth: { get: () => 1 } }); document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('div').__x.$data.defaultPrevented).toEqual(null) fireEvent.mouseDown(document.querySelector('span')) await wait(() => { expect(document.querySelector('div').__x.$data.defaultPrevented).toEqual(false) }) }) test('supports short syntax', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').getAttribute('foo')).toEqual('bar') document.querySelector('button').click() await wait(() => { expect(document.querySelector('span').getAttribute('foo')).toEqual('baz') }) }) test('event with colon', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').getAttribute('foo')).toEqual('bar') var event = new CustomEvent('my:event'); document.dispatchEvent(event); await wait(() => { expect(document.querySelector('span').getAttribute('foo')).toEqual('baz') }) }) test.skip('prevent default action when an event returns false', async () => { // This test is skipped because in a browser this works, but it won't // pass in this tests unless we bypass the promise resolving system // for the result of an event handler expression. window.confirm = jest.fn().mockReturnValue(false) document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('input').checked).toEqual(false) document.querySelector('input').click() expect(document.querySelector('input').checked).toEqual(false) window.confirm = jest.fn().mockReturnValue(true) document.querySelector('input').click() expect(document.querySelector('input').checked).toEqual(true) }) test('allow method reference to be passed to listeners', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').textContent).toEqual('bar') document.querySelector('button').click() await new Promise(resolve => setTimeout(resolve, 1)) expect(document.querySelector('span').textContent).toEqual('baz') }) test('event instance is passed to method reference', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').textContent).toEqual('bar') document.querySelector('button').click() await new Promise(resolve => setTimeout(resolve, 1)) expect(document.querySelector('span').textContent).toEqual('baz') }) test('autocomplete event does not trigger keydown with modifier callback', async () => { document.body.innerHTML = `
` Alpine.start() expect(document.querySelector('span').textContent).toEqual('0') const autocompleteEvent = new Event('keydown') fireEvent.keyDown(document.querySelector('input'), { key: 'Enter' }) await wait(() => { expect(document.querySelector('span').textContent).toEqual('0') }) fireEvent.keyDown(document.querySelector('input'), { key: '?' }) await wait(() => { expect(document.querySelector('span').textContent).toEqual('1') }) fireEvent(document.querySelector('input'), autocompleteEvent) await wait(() => { expect(document.querySelector('span').textContent).toEqual('1') }) }) test('.camel modifier correctly binds event listener', async () => { document.body.innerHTML = `

` Alpine.start() expect(document.querySelector('p').textContent).toEqual('bar') document.querySelector('button').click(); await wait(() => { expect(document.querySelector('p').textContent).toEqual('bob'); }); }) test('.camel modifier correctly binds event listener with namespace', async () => { document.body.innerHTML = `

` Alpine.start() expect(document.querySelector('p').textContent).toEqual('bar') document.querySelector('button').click(); await wait(() => { expect(document.querySelector('p').textContent).toEqual('bob'); }); })