Last active
December 23, 2024 14:55
-
-
Save cferdinandi/8ebc5e189a42827edc0020628bd84bc9 to your computer and use it in GitHub Desktop.
Source code for this article: https://gomakethings.com/testing-dom-manipulation/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8" /> | |
<title>Mocha Tests</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" /> | |
</head> | |
<body> | |
<div id="mocha"></div> | |
<script src="https://unpkg.com/chai@4/chai.js"></script> | |
<script src="https://unpkg.com/mocha/mocha.js"></script> | |
<script class="mocha-init"> | |
mocha.setup('bdd'); | |
mocha.checkLeaks(); | |
window.addEventListener('load', function () { | |
mocha.run(); | |
}); | |
</script> | |
<script src="show-hide.js"></script> | |
<script src="tests.dom-helpers.js"></script> | |
<script src="test.show-hide.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
customElements.define('show-hide', class extends HTMLElement { | |
/** | |
* Instantiate the Web Component | |
*/ | |
constructor () { | |
// Get parent class properties | |
super(); | |
// Get the elements | |
this.trigger = this.querySelector('[trigger]'); | |
this.content = this.querySelector('[content]'); | |
if (!this.trigger || !this.content) return; | |
// Setup default UI | |
this.trigger.removeAttribute('hidden'); | |
this.trigger.setAttribute('aria-expanded', false); | |
this.content.setAttribute('hidden', ''); | |
// Listen for click events | |
if (!this.trigger || !this.content) return; | |
this.trigger.addEventListener('click', this); | |
} | |
/** | |
* Handle events | |
* @param {Event} event The event object | |
*/ | |
handleEvent (event) { | |
// Don't let the button trigger other actions | |
event.preventDefault(); | |
// If the content is expanded, hide it | |
// Otherwise, show it | |
if (this.trigger.getAttribute('aria-expanded') === 'true') { | |
this.trigger.setAttribute('aria-expanded', false); | |
this.content.setAttribute('hidden', ''); | |
} else { | |
this.trigger.setAttribute('aria-expanded', true); | |
this.content.removeAttribute('hidden'); | |
} | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const {expect} = chai; | |
describe('The <show-hide> Web Component', function () { | |
// | |
// Test Setup | |
// | |
// Create a DOM node to inject content into | |
let app = document.createElement('div'); | |
document.body.append(app); | |
// Get the Web Component elements from the DOM | |
function getElements () { | |
return { | |
wc: app.querySelector('show-hide'), | |
trigger: app.querySelector('[trigger]'), | |
content: app.querySelector('[content]'), | |
}; | |
} | |
// Clean up UI | |
after(function () { | |
app.remove(); | |
}); | |
// Inject fresh Web Component | |
beforeEach(function () { | |
app.innerHTML = | |
`<show-hide> | |
<button trigger hidden>Show Content</button> | |
<div content> | |
<p>Now you see me, now you don't!</p> | |
</div> | |
</show-hide>`; | |
}); | |
// | |
// Tests | |
// | |
it('Should hide content and make button visible on load', function () { | |
let {wc, trigger, content} = getElements(); | |
expect(trigger.hasAttribute('hidden')).to.equal(false); | |
expect(content.hasAttribute('hidden')).to.equal(true); | |
}); | |
it('Should add required ARIA attributes on load', function () { | |
let {trigger} = getElements(); | |
expect(trigger.getAttribute('aria-expanded')).to.equal('false'); | |
}); | |
it('Should show and hide content on click events', function () { | |
// Get elements | |
let {trigger, content} = getElements(); | |
// Show content on click | |
simulateClick(trigger); | |
expect(content.hasAttribute('hidden')).to.equal(false); | |
// Hide content if clicked again | |
simulateClick(trigger); | |
expect(content.hasAttribute('hidden')).to.equal(true); | |
}); | |
it('Should update ARIA on click events', function () { | |
// Get elements | |
let {trigger} = getElements(); | |
// Show content on click | |
simulateClick(trigger); | |
expect(trigger.getAttribute('aria-expanded')).to.equal('true'); | |
// Hide content if clicked again | |
simulateClick(trigger); | |
expect(trigger.getAttribute('aria-expanded')).to.equal('false'); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Helper functions for DOM tests | |
// | |
/** | |
* Simulate an event | |
* @param {Element} elem The element to simulate a click on | |
* @param {String} type The event type to simulate | |
*/ | |
function simulateEvent (elem, type) { | |
// Create a new event | |
var event = new Event(type, { | |
bubbles: true, | |
cancellable: true | |
}); | |
// Dispatch the event | |
return elem.dispatchEvent(event); | |
} | |
/** | |
* Simulate a click event | |
* @param {Element} elem the element to simulate a click on | |
*/ | |
function simulateClick (elem) { | |
elem.click(); | |
} | |
/** | |
* Simulate a click event | |
* @param {String} key The key to simulate | |
* @param {Element} elem the element to simulate a click on | |
* @param {String} type The type of keyboard event to simulate | |
*/ | |
function simulateKeyboard (key, elem = document, type = 'keydown') { | |
let event = new KeyboardEvent(type, {key}); | |
return elem.dispatchEvent(event); | |
} |
@tbrlpld Good catch! That was a copy/paste error from a previous bit of code. I also updated the simulateClick()
method to use the more modern Element.click()
.
Thanks for explaining 👍
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Super interesting to see this in-browser only testing approach.
@cferdinandi One question about that last lines of the test helper: Why do you assign the return of the dispatch to a variable?
It does not seem to be used or returned. Is this for potential extension?