Ad/iklan :

3gp Mp4 HD
Play/Download
Live 3D App
Search.Pencarian Menu

Add text send email to rh3252705.adda@blogger.com or Click this (Text porn Will delete) | Tambah teks kirim email ke rh3252705.adda@blogger.com atau Klik ini (Teks porno akan dihapus)
Total post.pos : 15909+

[Go Make Things] Testing DOM manipulation and Web Components

So far in our series about testing JavaScript, we've looked at how to write tests for code that's mostly logic-based.

Today, we'll look at how to write tests for a DOM manipulation library or Web Component. Let's dig in!

The Library

Today, we'll be testing my <show-hide> Web Component, which let's you create some content that you can show or hide whenever a <button> is clicked.

(Yes, I know about <details> and <summary>! This is a good, simple example for teaching.)

To use it, wrap a <button> and some content to selectively show or hide in the <show-hide> component.

Add the [trigger] and [hidden] attributes to the toggle <button>. Add the [content] attribute to the content to show or hide.

<show-hide>  	<button trigger hidden>Show Content</button>    	<div content>  		<p>Now you see me, now you don't!</p>  	</div>  </show-hide>

When the Web Component loads, it will display the button, hide the content, add required ARIA attributes, and add event listeners to selectively show or hide the [content] when the [trigger] is clicked.

It also adds the [aria-expanded] attribute to the [trigger], which tells screen readers what the <button> behavior is and its current state.

/**   * 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);    }  

When the [trigger] is clicked, the [hidden] attribute is added or removed to the [content], and the value of the [aria-expanded] attribute is updated.

/**   * 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');  	}    }  

You can download the Web Component JavaScript and the rest of the code for today's article on GitHub.

What we're going to test

Thinking about this from a TDD approach (this isn't really TDD because the code is already written), the external behaviors we need are…

  • On load, the [trigger] should be visible and the [content] should be hidden.
  • On load, the required ARIA attributes should be added.
  • When the [trigger] is clicked, the content should be shown or hidden, depending on its current state.
  • When the [trigger] is clicked, the [aria-expanded] attribute value should change to reflect the current state.

We can start by stumping out our tests…

const {expect} = chai;    describe('The <show-hide> Web Component', function () {    	it('Should hide content and make button visible on load', function () {  		// ...  	});    	it('Should add required ARIA attributes on load', function () {  		// ...  	});    	it('Should show and hide content on click events', function () {  		// ...  	});    	it('Should update ARIA on click events', function () {  		// ...  	});    });  

Because we're testing DOM manipulation, there are a few things we need to do that we don't with plain old logic tests.

Testing the DOM

In command line (CLI) testing libraries, you typically need to install a JS-based DOM simulator that replicates the browser engine.

Because we're going buildless and opening up a real browser, we don't have to worry about that! We have full access to all of the native browser methods.

What we don't have is the ability to actually scroll, click, and press keys in the UI. For those, we'll have to simulate events to run our tests.

I've put together a tests.dom-helpers.js file that contains functions to simulate click events, keyboard events, and other generic events.

// Get our target element  let btn = document.querySelector('button');    // Simulate a click on the button  simulateClick(btn)    // Simulate a return key keyboard event on the button  simulateKeyboard('Return', btn);    // Simulate any other type of event (in this case a mouseenter event)  simulateEvent(elem, 'mouseenter');  

This file is available in the source code, and over at the Lean Web Club.

Test setup

While you could just hard-code the HTML for the test into the test HTML file, it's probably a good idea to setup a fresh component before each test, and tear it down after each one to ensure code from a previous test doesn't mess up the current one.

Most testing frameworks offer a way to do that.

In Mocha, you can run before(), after(), beforeEach(), and afterEach() methods, which run before all tests, after all tests, before each test, and after each test respectively.

For our purposes, we'll create a new app element and inject it into the document.body.

Before each test, we'll inject a fresh copy of our <show-hide> element. And after all the tests are done, we'll remove the app element entirely.

// Create a DOM node to inject content into  let app = document.createElement('div');  document.body.append(app);    // 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>`;  });    // Clean up UI  after(function () {  	app.remove();  });  

Because we'll need to keep grabbing our elements over-and-over again, I also added a getElements() method that searches for our elements in the DOM, and returns an object ({}) with with references to each of our elements.

// Get the Web Component elements from the DOM  function getElements () {  	return {  		wc: app.querySelector('show-hide'),  		trigger: app.querySelector('[trigger]'),  		content: app.querySelector('[content]'),    	};  }  

Writing the tests

Our on load tests are the easiest to write.

We'll use our getElements() method and object destructuring to get the elements we want to test.

Then, we'll use the Element.hasAttribute() and Element.getAttribute() methods to ensure the require attributes are there, aren't there, or have the correct value, respectively.

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');  });  

To test click behavior, we'll again get our elements.

Then, we'll run the simulateClick() method on the trigger, and check that the [hidden] attribute has been removed from the content. We'll run simulateClick() again, and make sure the [hidden] element was added back.

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);    });  

We'll run a similar test for the [aria-expanded] attribute on the trigger, this time checking its value, not just that it exists.

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');    });  

Other tests you might run

It's probably a good idea to also test edge cases and error behaviors.

What happens, for example, if the user doesn't add required attributes like [trigger] and [content]. If you want to play around with this yourself, try writing tests for those behaviors.

Download the complete source code on GitHub.

Cheers,
Chris

Want to share this with others or read it later? View it in a browser.

Share :

Facebook Twitter Google+
0 Komentar untuk "[Go Make Things] Testing DOM manipulation and Web Components"

Back To Top