Skip to content

Commit

Permalink
Fix the draggable attribute & flesh out enumerated property support.
Browse files Browse the repository at this point in the history
The dragabble attribute was not being correctly recognised - when
specified it must have only two values, the strings "true" and
"false". Previously it was treated as a boolean attribute, which
lead to true being accepted while false did not work at all.

Change this so the only acceptable values are the two supported
strings. Add some belt and braces when specifying the value in an
object spec so you cannot accidentally specify an unsupported value.
  • Loading branch information
alexjeffburke committed Sep 24, 2018
1 parent 6494056 commit d00e763
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 18 deletions.
51 changes: 33 additions & 18 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,14 @@ var enumeratedAttributeValues = {
draggable: ['true', 'false'] // defaults to 'auto'
};

function isBooleanAttribute(attrName, attrValue) {
var isSimpleBoolean = /^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|spellcheck|truespeed|typemustmatch|visible)$/i.test(
attrName
);
if (isSimpleBoolean) {
return true;
}
var matchSimpleAttribute = /^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|spellcheck|truespeed|typemustmatch|visible)$/i;

var attrValueEnumeration = enumeratedAttributeValues[attrName.toLowerCase()];
if (!attrValueEnumeration) {
return false;
} else {
return attrValueEnumeration.indexOf(attrValue.toLowerCase()) === -1;
}
function isBooleanAttribute(attrName) {
return matchSimpleAttribute.test(attrName);
}

function isEnumeratedAttribute(attrName) {
return attrName in enumeratedAttributeValues;
}

function styleStringToObject(str) {
Expand Down Expand Up @@ -210,7 +204,7 @@ function writeAttributeToMagicPen(output, attributeName, value, isHtml) {
}

function stringifyAttribute(attributeName, value) {
if (isBooleanAttribute(attributeName)) {
if (isBooleanAttribute(attributeName) || isEnumeratedAttribute(attributeName)) {
return attributeName;
} else if (attributeName === 'class') {
return 'class="' + value.join(' ') + '"'; // FIXME: entitify
Expand Down Expand Up @@ -1042,13 +1036,34 @@ module.exports = {
var expectedAttributeValue =
expectedValueByAttributeName[attributeName];
promiseByKey.attributes[attributeName] = expect.promise(function() {
if (expectedAttributeValue === true) {
if (typeof expectedAttributeValue === 'undefined') {
return bubbleError(function() {
expect(subject.hasAttribute(attributeName), 'to be true');
expect(subject.hasAttribute(attributeName), 'to be false');
});
} else if (typeof expectedAttributeValue === 'undefined') {
} else if (isEnumeratedAttribute(attributeName)) {
return bubbleError(function() {
expect(subject.hasAttribute(attributeName), 'to be false');
var indexOfEnumeratedAttributeValue = enumeratedAttributeValues[attributeName].indexOf(expectedAttributeValue);
if (indexOfEnumeratedAttributeValue === -1) {
expect.withError(function() {
expect(enumeratedAttributeValues[attributeName], 'to contain', expectedAttributeValue);
}, function(e) {
expect.fail({
message: function(output) {
output
.text('Invalid expected value ')
.appendInspected(expectedAttributeValue)
.text('. Supported values include: ')
.appendInspected(enumeratedAttributeValues[attributeName]);
}
});
});
}

expect(attributeValue, 'to satisfy', expectedAttributeValue);
});
} else if (expectedAttributeValue === true) {
return bubbleError(function() {
expect(subject.hasAttribute(attributeName), 'to be true');
});
} else if (
attributeName === 'class' &&
Expand Down
55 changes: 55 additions & 0 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1211,6 +1211,61 @@ describe('unexpected-dom', function() {
);
});

describe('with boolean attributes', function() {
describe('draggable', () => {
it('should allow "true"', function() {
body.innerHTML = '<div draggable="true"></div>';
expect(body, 'to satisfy', {
children: [
{
attributes: {
draggable: 'true'
}
}
]
});
});

it('should allow "false"', function() {
body.innerHTML = '<div draggable="false"></div>';
expect(body, 'to satisfy', {
children: [
{
attributes: {
draggable: 'false'
}
}
]
});
});

it('should error on mismatch', function() {
body.innerHTML = '<div draggable="true"></div>';
expect(
function() {
expect(body, 'to satisfy', {
children: [
{
attributes: {
draggable: false
}
}
]
})
},
'to throw',
'expected <body><div draggable></div></body> to satisfy { children: [ { attributes: ... } ] }\n' +
'\n' +
'<body>\n' +
' <div\n' +
" draggable=\"true\" // Invalid expected value false. Supported values include: [ 'true', 'false' ]\n" +
' ></div>\n' +
'</body>'
);
});
});
});

describe('with a textContent property', function() {
it('should succeed', function() {
body.innerHTML = '<div foo="bar">foobarquux</div>';
Expand Down

0 comments on commit d00e763

Please sign in to comment.