Skip to content

Commit

Permalink
Update ember input serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
Robdel12 committed Sep 11, 2019
1 parent e387464 commit 87f8894
Showing 1 changed file with 63 additions and 32 deletions.
95 changes: 63 additions & 32 deletions addon/snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,41 +20,70 @@ function getDoctype() {
return doctype;
}

const FORM_ELEMENTS_SELECTOR = 'input, textarea, select';

function mutateOriginalDOM(dom) {
function createUID($el) {
const ID = `_${Math.random().toString(36).substr(2, 9)}`;

$el.setAttribute('data-percy-element-id', ID)
}

let formNodes = dom.querySelectorAll(FORM_ELEMENTS_SELECTOR)
let formElements = Array.from(formNodes);

// loop through each form element and apply an ID for serialization later
formElements.forEach((elem) => {
if (!elem.getAttribute('data-percy-element-id')) {
createUID(elem)
}
})
}

// Set the property value into the attribute value for snapshotting inputs
function setAttributeValues(dom) {
// List of input types here https://www.w3.org/TR/html5/forms.html#the-input-element

// Limit scope to inputs only as textareas do not retain their value when cloned
let elems = dom.find(
`input[type=text], input[type=search], input[type=tel], input[type=url], input[type=email],
input[type=password], input[type=number], input[type=checkbox], input[type=radio]`
);

percyJQuery(elems).each(function() {
let elem = percyJQuery(this);
switch(elem.attr('type')) {
function setAttributeValues(originalDOM, clonedDOM) {
let formNodes = originalDOM.querySelectorAll(FORM_ELEMENTS_SELECTOR)
let formElements = Array.from(formNodes);

formElements.forEach(elem => {
let inputId = elem.getAttribute('data-percy-element-id')
let selector = `[data-percy-element-id="${inputId}"]`;
let cloneEl = clonedDOM.querySelector(selector)

if(!cloneEl) return;

switch (elem.type) {
case 'checkbox':
case 'radio':
if (elem.is(':checked')) {
elem.attr('checked', '');
if (elem.checked) {
cloneEl.setAttribute('checked', '')
}
break
case 'select-one':
if (elem.selectedIndex !== -1) {
cloneEl.options[elem.selectedIndex].setAttribute('selected', 'true');
}
break
case 'select-multiple':
let selectedOptions = Array.from(elem.selectedOptions); // eslint-disable-line
let clonedOptions = Array.from(cloneEl.options); // eslint-disable-line

if (selectedOptions.length) {
selectedOptions.forEach((option) => {
const matchingOption = clonedOptions.find((cloneOption) => option.text === cloneOption.text)
matchingOption.setAttribute('selected', 'true')
})
}
break;

break
case 'textarea':
// setting text or value does not work but innerHTML does
cloneEl.innerHTML = elem.value
break
default:
elem.attr('value', elem.val());
cloneEl.setAttribute('value', elem.value)
}
});

return dom;
}

// jQuery clone() does not copy textarea contents, so we explicitly do it here.
function setTextareaContent(dom) {
dom.find('textarea').each(function() {
let elem = percyJQuery(this);
elem.text(elem.val());
});

return dom;
})
}

// Copy attributes from Ember's rootElement to the DOM snapshot <body> tag. Some applications rely
Expand Down Expand Up @@ -95,7 +124,9 @@ export function percySnapshot(name, options) {
let scope = options.scope;

// Create a full-page DOM snapshot from the current testing page.
let domCopy = percyJQuery('html').clone();
let dom = percyJQuery('html');
mutateOriginalDOM(dom[0]);
let domCopy = dom.clone();
let bodyCopy = domCopy.find('body');
let testingContainer = domCopy.find('#ember-testing');

Expand All @@ -107,8 +138,8 @@ export function percySnapshot(name, options) {
snapshotRoot = testingContainer;
}

snapshotRoot = setAttributeValues(snapshotRoot);
snapshotRoot = setTextareaContent(snapshotRoot);
// Pass the actual DOM nodes, not the jquery object
setAttributeValues(dom[0], snapshotRoot[0]);

let snapshotHtml = snapshotRoot.html();

Expand Down

0 comments on commit 87f8894

Please sign in to comment.