diff --git a/packages/test-helpers/canonicalize_html.js b/packages/test-helpers/canonicalize_html.js
index ba1868d0a3..9f6d369a78 100644
--- a/packages/test-helpers/canonicalize_html.js
+++ b/packages/test-helpers/canonicalize_html.js
@@ -31,12 +31,15 @@ canonicalizeHtml = function(html) {
attrs = attrs.replace(/\s+/g, ' ');
// quote unquoted attribute values, as in `type=checkbox`. This
// will do the wrong thing if there's an `=` in an attribute value.
- attrs = attrs.replace(/(\w)=([^" >/]+)/g, '$1="$2"');
- // for the purpose of splitting attributes in a string like
- // 'a="b" c="d"', assume they are separated by a single space
- // and values are double-quoted, but allow for spaces inside
- // the quotes. Split on space following quote.
- var attrList = attrs.replace(/" /g, '"\u0000').split('\u0000');
+ attrs = attrs.replace(/(\w)=([^'" >/]+)/g, '$1="$2"');
+
+ // for the purpose of splitting attributes in a string like 'a="b"
+ // c="d"', assume they are separated by a single space and values
+ // are double- or single-quoted, but allow for spaces inside the
+ // quotes. Split on space following quote.
+ var attrList = attrs.replace(/(\w)='([^']+)' /g, "$1='$2'\u0000");
+ attrList = attrList.replace(/(\w)="([^"]+)" /g, '$1="$2"\u0000');
+ attrList = attrList.split("\u0000");
// put attributes in alphabetical order
attrList.sort();
@@ -59,11 +62,21 @@ canonicalizeHtml = function(html) {
if (key === 'sizset')
continue;
var value = a[1];
- value = value.replace(/["'`]/g, '"');
- // this check is probably made unreachable by a regex above
- // that quotes unquoted attribute values
- if (value.charAt(0) !== '"')
- value = '"'+value+'"';
+
+ // make sure the attribute is doubled-quoted
+ if (value.charAt(0) === '"') {
+ // Do nothing
+ } else {
+ if (value.charAt(0) !== "'") {
+ // attribute is unquoted. should be unreachable because of
+ // regex above.
+ value = '"' + value + '"';
+ } else {
+ // attribute is single-quoted. make it double-quoted.
+ value = value.replace(/\"/g, """);
+ }
+ value = value.replace(/["'`]/g, '"');
+ }
tagContents.push(key+'='+value);
}
return '<'+tagContents.join(' ')+'>';
diff --git a/packages/ui/render_tests.js b/packages/ui/render_tests.js
index 3c0ac08834..b2599ec647 100644
--- a/packages/ui/render_tests.js
+++ b/packages/ui/render_tests.js
@@ -271,18 +271,18 @@ Tinytest.add("ui - render - reactive attributes", function (test) {
// Test styles.
(function () {
// Test the case where there is a semicolon in the css attribute.
- var R = ReactiveVar({'style': 'foo:"a;aa"; bar: b;',
+ var R = ReactiveVar({'style': 'foo: "a;aa"; bar: b;',
id: 'foo'});
var spanCode = SPAN({$dynamic: [function () { return R.get(); }]});
- test.equal(toHTML(spanCode), '');
+ test.equal(toHTML(spanCode), '');
test.equal(R.numListeners(), 0);
var div = document.createElement("DIV");
materialize(spanCode, div);
- test.equal(canonicalizeHtml(div.innerHTML), '');
+ test.equal(canonicalizeHtml(div.innerHTML), '');
test.equal(R.numListeners(), 1);
@@ -292,7 +292,7 @@ Tinytest.add("ui - render - reactive attributes", function (test) {
R.set({'style': 'foo:"a;zz;aa"', id: 'bar'});
Deps.flush();
- test.equal(canonicalizeHtml(div.innerHTML), '');
+ test.equal(canonicalizeHtml(div.innerHTML, true), '');
test.equal(R.numListeners(), 1);
R.set({});
@@ -675,4 +675,4 @@ Tinytest.add("ui - UI.render _nestInCurrentComputation flag", function (test) {
test.equal(firstComputation.stopped, false);
}
});
-});
\ No newline at end of file
+});