You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1327 lines
35 KiB
1327 lines
35 KiB
1 month ago
|
const { toXML } = require("./dist/jstoxml");
|
||
|
const assert = require("assert");
|
||
|
|
||
|
describe("toXML", () => {
|
||
|
describe("primitives", () => {
|
||
|
const vals = ["foo", false, true, 4, 4.56];
|
||
|
|
||
|
vals.forEach((val) => {
|
||
|
it(`outputs ${val}`, () => {
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = `${val}`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("functions", () => {
|
||
|
describe("primitive outputs", () => {
|
||
|
const vals = [999, "foo", false, true];
|
||
|
|
||
|
vals.forEach((val) => {
|
||
|
it(`${val}`, () => {
|
||
|
const result = toXML(() => val);
|
||
|
const expectedResult = `${val}`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it("fat arrow", () => {
|
||
|
const val = 888;
|
||
|
const result = toXML(() => val);
|
||
|
const expectedResult = val;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("accessing config within function", () => {
|
||
|
const val = {
|
||
|
foo: {
|
||
|
depth: (config) => config.depth,
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<foo><depth>2</depth></foo>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("converts nonprimitive output", () => {
|
||
|
const val = { foo: "bar" };
|
||
|
const result = toXML(() => val);
|
||
|
const expectedResult = "<foo>bar</foo>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("converts nested nonprimitive output", () => {
|
||
|
const val = { foo: { bar: { baz: 2 } } };
|
||
|
const result = toXML(() => val);
|
||
|
const expectedResult = "<foo><bar><baz>2</baz></bar></foo>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("converts nested nonprimitive output with indent", () => {
|
||
|
const val = { foo: { bar: { baz: 2 } } };
|
||
|
const config = { indent: " " };
|
||
|
const result = toXML(() => val, config);
|
||
|
const expectedResult =
|
||
|
"<foo>\n <bar>\n <baz>2</baz>\n </bar>\n</foo>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("github issues", () => {
|
||
|
it("issue 3", () => {
|
||
|
const val = {
|
||
|
foo: true,
|
||
|
bar: "",
|
||
|
foo2: false,
|
||
|
ok: "This is ok",
|
||
|
ok2: "false",
|
||
|
ok3: "true",
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult =
|
||
|
"<foo>true</foo><bar/><foo2>false</foo2><ok>This is ok</ok><ok2>false</ok2><ok3>true</ok3>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("arrays", () => {
|
||
|
it("1", () => {
|
||
|
const val = [{ foo: "bar" }, { foo: "baz" }, { foo2: "bar2" }];
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<foo>bar</foo><foo>baz</foo><foo2>bar2</foo2>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("attributes in subobject", () => {
|
||
|
const val = [
|
||
|
{ foo: "bar" },
|
||
|
{ foo: "baz" },
|
||
|
{ foo: undefined },
|
||
|
{ foo: "" },
|
||
|
{ foo: null },
|
||
|
{
|
||
|
_name: "foo",
|
||
|
_content: "bar",
|
||
|
_attrs: {
|
||
|
a: "b",
|
||
|
c: "d",
|
||
|
},
|
||
|
},
|
||
|
];
|
||
|
const result = toXML(val);
|
||
|
const expectedResult =
|
||
|
'<foo>bar</foo><foo>baz</foo><foo/><foo/>foo<foo a="b" c="d">bar</foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("nesting with indent", () => {
|
||
|
const val = {
|
||
|
foo: [{ foo: "bar" }, { foo: "baz" }, { foo2: "bar2" }],
|
||
|
};
|
||
|
const config = { indent: " " };
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult = `<foo>
|
||
|
<foo>bar</foo>
|
||
|
<foo>baz</foo>
|
||
|
<foo2>bar2</foo2>
|
||
|
</foo>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("special-objects", () => {
|
||
|
it("1", () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_content: "bar",
|
||
|
_attrs: {
|
||
|
a: 1,
|
||
|
b: 2,
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = '<foo a="1" b="2">bar</foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("2", () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_content: {
|
||
|
foo: "bar",
|
||
|
},
|
||
|
_attrs: {
|
||
|
a: 1,
|
||
|
b: 2,
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = '<foo a="1" b="2"><foo>bar</foo></foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("3", () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_content: () => 1 + 2,
|
||
|
_attrs: {
|
||
|
a: 1,
|
||
|
b: 2,
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = '<foo a="1" b="2">3</foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("objects", () => {
|
||
|
it("1", () => {
|
||
|
const val = {
|
||
|
foo: "bar",
|
||
|
foo2: "bar2",
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<foo>bar</foo><foo2>bar2</foo2>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("attributes", () => {
|
||
|
const val = {
|
||
|
_name: "a",
|
||
|
_attrs: {
|
||
|
foo: "bar",
|
||
|
foo2: "bar2",
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = '<a foo="bar" foo2="bar2"/>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("attributes 2", () => {
|
||
|
const val = {
|
||
|
_name: "a",
|
||
|
_attrs: {
|
||
|
foo: "bar",
|
||
|
foo2: "bar2",
|
||
|
},
|
||
|
_content: "la dee da",
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = '<a foo="bar" foo2="bar2">la dee da</a>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("attributes nesting", () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_attrs: {
|
||
|
a: "b",
|
||
|
},
|
||
|
_content: {
|
||
|
_name: "bar",
|
||
|
_attrs: {
|
||
|
c: "d",
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = '<foo a="b"><bar c="d"/></foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
it("with mixed content", () => {
|
||
|
const val = {
|
||
|
blah: null,
|
||
|
foo: "bar",
|
||
|
"more blah": null,
|
||
|
bar: 0,
|
||
|
"more more blah": null,
|
||
|
baz: false,
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult =
|
||
|
"blah<foo>bar</foo>more blah<bar>0</bar>more more blah<baz>false</baz>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("nesting with indent", () => {
|
||
|
const val = {
|
||
|
foo: {
|
||
|
foo: "bar",
|
||
|
foo2: "bar2",
|
||
|
},
|
||
|
};
|
||
|
const config = { indent: " " };
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult = `<foo>
|
||
|
<foo>bar</foo>
|
||
|
<foo2>bar2</foo2>
|
||
|
</foo>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("deep nesting", () => {
|
||
|
const val = {
|
||
|
a: {
|
||
|
b: {
|
||
|
c: {
|
||
|
d: {
|
||
|
e: {
|
||
|
f: {
|
||
|
g: {
|
||
|
h: {
|
||
|
i: {
|
||
|
j: {
|
||
|
k: {
|
||
|
l: {
|
||
|
m: {
|
||
|
foo: "bar",
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult =
|
||
|
"<a><b><c><d><e><f><g><h><i><j><k><l><m><foo>bar</foo></m></l></k></j></i></h></g></f></e></d></c></b></a>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("header", () => {
|
||
|
it("default header", () => {
|
||
|
const val = {
|
||
|
foo: "bar",
|
||
|
};
|
||
|
const config = {
|
||
|
header: true,
|
||
|
};
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult =
|
||
|
'<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("no header", () => {
|
||
|
const val = {
|
||
|
foo: "bar",
|
||
|
};
|
||
|
const config = {
|
||
|
header: false,
|
||
|
};
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult = "<foo>bar</foo>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("no header by default", () => {
|
||
|
const val = {
|
||
|
foo: "bar",
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<foo>bar</foo>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("default header with indent", () => {
|
||
|
const val = {
|
||
|
foo: "bar",
|
||
|
};
|
||
|
const config = {
|
||
|
header: true,
|
||
|
indent: " ",
|
||
|
};
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult =
|
||
|
'<?xml version="1.0" encoding="UTF-8"?>\n<foo>bar</foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("custom header", () => {
|
||
|
const val = {
|
||
|
foo: "bar",
|
||
|
};
|
||
|
const config = {
|
||
|
header: '<?FOO BAR="123" BAZ="XX"?>',
|
||
|
};
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult = '<?FOO BAR="123" BAZ="XX"?><foo>bar</foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("custom header 2", () => {
|
||
|
const val = [
|
||
|
{
|
||
|
row: 'bar'
|
||
|
},
|
||
|
{
|
||
|
row: 'bar2'
|
||
|
}
|
||
|
];
|
||
|
const config = {
|
||
|
header: '<?xml version="1.0" encoding="UTF-16" standalone="yes"?>',
|
||
|
indent: ' '
|
||
|
};
|
||
|
|
||
|
const result = toXML(val, config);
|
||
|
|
||
|
const expectedResult = `<?xml version="1.0" encoding="UTF-16" standalone="yes"?>
|
||
|
<row>bar</row>
|
||
|
<row>bar2</row>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
})
|
||
|
});
|
||
|
|
||
|
describe("filtering", () => {
|
||
|
it("values", () => {
|
||
|
const val = {
|
||
|
foo: "<a>",
|
||
|
bar: '"b"',
|
||
|
baz: "'&whee'",
|
||
|
};
|
||
|
const config = {
|
||
|
filter: {
|
||
|
"<": "<",
|
||
|
">": ">",
|
||
|
'"': """,
|
||
|
"'": "'",
|
||
|
"&": "&",
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult =
|
||
|
"<foo><a></foo><bar>"b"</bar><baz>'&whee'</baz>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("attributes", () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_attrs: { a: '<"\'&"foo>' },
|
||
|
};
|
||
|
const config = {
|
||
|
attributesFilter: {
|
||
|
"<": "<",
|
||
|
">": ">",
|
||
|
'"': """,
|
||
|
"'": "'",
|
||
|
"&": "&",
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult = '<foo a="<"'&"foo>"/>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
const entities = {
|
||
|
"&": "&",
|
||
|
"<": "<",
|
||
|
">": ">",
|
||
|
};
|
||
|
|
||
|
Object.entries(entities).forEach(([entity, entityEncoded]) => {
|
||
|
it(`filters '${entity}' entities by default`, () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_attrs: { a: `aaa ${entity} bbb` },
|
||
|
_content: `foo ${entity} bar`,
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = `<foo a="aaa ${entityEncoded} bbb">foo ${entityEncoded} bar</foo>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it(`filters entities by default 2`, () => {
|
||
|
const val = {
|
||
|
foo: '1 < 2 & 2 > 1'
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = `<foo>1 < 2 & 2 > 1</foo>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("does not double encode", () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_attrs: { a: "baz & > < bat" },
|
||
|
_content: "foo & > < bar",
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult =
|
||
|
'<foo a="baz & > < bat">foo & > < bar</foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("does not double encode 2", () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_attrs: { a: "baz && &> &< bat" },
|
||
|
_content: "foo && &> &< bar",
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult =
|
||
|
'<foo a="baz && &> &< bat">foo && &> &< bar</foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("does not double encode 3", () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_attrs: { a: "¢ ¢ € € &eu ro;" },
|
||
|
_content: "¢ ¢ € € &eu ro;",
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult =
|
||
|
'<foo a="¢ ¢ € € &eu ro;">¢ ¢ € € &eu ro;</foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("escapes quotes in attributes by default", () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_attrs: { a: '"bat"' },
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = '<foo a=""bat""/>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it(`turns off attributes filter`, () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_attrs: { a: "baz & < > \" bat" },
|
||
|
_content: "foo & < > bar",
|
||
|
};
|
||
|
const result = toXML(val, { attributesFilter: false });
|
||
|
const expectedResult = `<foo a="baz & < > \" bat">foo & < > bar</foo>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it(`turns off filter`, () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_attrs: { a: "baz & < > \" bat" },
|
||
|
_content: "foo & < > bar",
|
||
|
};
|
||
|
const result = toXML(val, { filter: false });
|
||
|
const expectedResult = `<foo a="baz & < > " bat">foo & < > bar</foo>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it(`turns off both filter and attributesFilter`, () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_attrs: { a: "baz & < > \" bat" },
|
||
|
_content: "foo & < > bar",
|
||
|
};
|
||
|
const result = toXML(val, { filter: false, attributesFilter: false });
|
||
|
const expectedResult = `<foo a="baz & < > \" bat">foo & < > bar</foo>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("misc", () => {
|
||
|
it("outputs <_content> if it has no tag name", () => {
|
||
|
const val = {
|
||
|
_content: "foo",
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<_content>foo</_content>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("outputs emoji attributes", () => {
|
||
|
const val = {
|
||
|
html: {
|
||
|
_attrs: [{ "⚡": true }, { lang: "en" }, { lang: "klingon" }],
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val, { attributesFilter: {} });
|
||
|
const expectedResult = '<html ⚡ lang="en" lang="klingon"/>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("outputs emoji attributes 2", () => {
|
||
|
const val = {
|
||
|
html: {
|
||
|
_attrs: { "⚡": true, lang: "en" },
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val, { attributesFilter: {} });
|
||
|
const expectedResult = '<html ⚡ lang="en"/>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("does not force self close if tag has content", () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_selfCloseTag: true,
|
||
|
_content: "bar",
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<foo>bar</foo>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("nested elements with self-closing sibling", () => {
|
||
|
const val = {
|
||
|
people: {
|
||
|
students: [
|
||
|
{
|
||
|
student: { name: "Joe" },
|
||
|
},
|
||
|
{
|
||
|
student: { name: "Jane" },
|
||
|
},
|
||
|
],
|
||
|
teacher: {
|
||
|
_selfCloseTag: true,
|
||
|
_attrs: {
|
||
|
name: "Yoda",
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult =
|
||
|
'<people><students><student><name>Joe</name></student><student><name>Jane</name></student></students><teacher name="Yoda"/></people>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("sibling _content tag", () => {
|
||
|
const val = {
|
||
|
foo: {
|
||
|
bar: "baz",
|
||
|
_content: {
|
||
|
bar2: "baz2",
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<foo><bar>baz</bar><bar2>baz2</bar2></foo>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("examples", () => {
|
||
|
it("1 simple object", () => {
|
||
|
const val = {
|
||
|
foo: "bar",
|
||
|
foo2: "bar2",
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<foo>bar</foo><foo2>bar2</foo2>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("2 simple array", () => {
|
||
|
const val = [{ foo: "bar" }, { foo: "bar2" }];
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<foo>bar</foo><foo>bar2</foo>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("3 simple function", () => {
|
||
|
const date = new Date();
|
||
|
const val = {
|
||
|
currentTime: () => date,
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = `<currentTime>${date}</currentTime>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("4 attributes", () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_content: "bar",
|
||
|
_attrs: {
|
||
|
a: "b",
|
||
|
c: "d",
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = '<foo a="b" c="d">bar</foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("5 tags with mixed content", () => {
|
||
|
const val = {
|
||
|
text1: null,
|
||
|
foo: "bar",
|
||
|
text2: null,
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "text1<foo>bar</foo>text2";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("6 nested tags with indent", () => {
|
||
|
const val = {
|
||
|
a: {
|
||
|
foo: "bar",
|
||
|
foo2: "bar2",
|
||
|
},
|
||
|
};
|
||
|
const config = {
|
||
|
header: false,
|
||
|
indent: " ",
|
||
|
};
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult = `<a>
|
||
|
<foo>bar</foo>
|
||
|
<foo2>bar2</foo2>
|
||
|
</a>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("7 nested tags attributes", () => {
|
||
|
const val = {
|
||
|
ooo: {
|
||
|
_name: "foo",
|
||
|
_attrs: {
|
||
|
a: "b",
|
||
|
},
|
||
|
_content: {
|
||
|
_name: "bar",
|
||
|
_attrs: {
|
||
|
c: "d",
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
const config = {
|
||
|
header: false,
|
||
|
indent: " ",
|
||
|
};
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult = `<ooo>
|
||
|
<foo a="b">
|
||
|
<bar c="d"/>
|
||
|
</foo>
|
||
|
</ooo>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("8 complex functions", () => {
|
||
|
const val = {
|
||
|
someNestedXML: () => ({ foo: "bar" }),
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<someNestedXML><foo>bar</foo></someNestedXML>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("9 RSS feed", () => {
|
||
|
const date = new Date();
|
||
|
|
||
|
const val = {
|
||
|
_name: "rss",
|
||
|
_attrs: {
|
||
|
version: "2.0",
|
||
|
},
|
||
|
_content: {
|
||
|
channel: [
|
||
|
{ title: "RSS Example" },
|
||
|
{ description: "Description" },
|
||
|
{ link: "google.com" },
|
||
|
{ lastBuildDate: () => date },
|
||
|
{ pubDate: () => date },
|
||
|
{ language: "en" },
|
||
|
{
|
||
|
item: {
|
||
|
title: "Item title",
|
||
|
link: "Item link",
|
||
|
description: "Item Description",
|
||
|
pubDate: () => date,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
item: {
|
||
|
title: "Item2 title",
|
||
|
link: "Item2 link",
|
||
|
description: "Item2 Description",
|
||
|
pubDate: () => date,
|
||
|
},
|
||
|
},
|
||
|
],
|
||
|
},
|
||
|
};
|
||
|
const config = {
|
||
|
header: true,
|
||
|
indent: " ",
|
||
|
};
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult = `<?xml version="1.0" encoding="UTF-8"?>
|
||
|
<rss version="2.0">
|
||
|
<channel>
|
||
|
<title>RSS Example</title>
|
||
|
<description>Description</description>
|
||
|
<link>google.com</link>
|
||
|
<lastBuildDate>${date}</lastBuildDate>
|
||
|
<pubDate>${date}</pubDate>
|
||
|
<language>en</language>
|
||
|
<item>
|
||
|
<title>Item title</title>
|
||
|
<link>Item link</link>
|
||
|
<description>Item Description</description>
|
||
|
<pubDate>${date}</pubDate>
|
||
|
</item>
|
||
|
<item>
|
||
|
<title>Item2 title</title>
|
||
|
<link>Item2 link</link>
|
||
|
<description>Item2 Description</description>
|
||
|
<pubDate>${date}</pubDate>
|
||
|
</item>
|
||
|
</channel>
|
||
|
</rss>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("10 podcast RSS", () => {
|
||
|
const val = {
|
||
|
_name: "rss",
|
||
|
_attrs: {
|
||
|
"xmlns:itunes": "http://www.itunes.com/dtds/podcast-1.0.dtd",
|
||
|
version: "2.0",
|
||
|
},
|
||
|
_content: {
|
||
|
channel: [
|
||
|
{ title: "Title" },
|
||
|
{ link: "google.com" },
|
||
|
{ language: "en-us" },
|
||
|
{ copyright: "Copyright 2011" },
|
||
|
{ "itunes:subtitle": "Subtitle" },
|
||
|
{ "itunes:author": "Author" },
|
||
|
{ "itunes:summary": "Summary" },
|
||
|
{ description: "Description" },
|
||
|
{
|
||
|
"itunes:owner": {
|
||
|
"itunes:name": "Name",
|
||
|
"itunes:email": "Email",
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
_name: "itunes:image",
|
||
|
_attrs: {
|
||
|
href: "image.jpg",
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
_name: "itunes:category",
|
||
|
_attrs: {
|
||
|
text: "Technology",
|
||
|
},
|
||
|
_content: {
|
||
|
_name: "itunes:category",
|
||
|
_attrs: {
|
||
|
text: "Gadgets",
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
_name: "itunes:category",
|
||
|
_attrs: {
|
||
|
text: "TV & Film",
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
item: [
|
||
|
{ title: "Podcast Title" },
|
||
|
{ "itunes:author": "Author" },
|
||
|
{ "itunes:subtitle": "Subtitle" },
|
||
|
{ "itunes:summary": "Summary" },
|
||
|
{ "itunes:image": "image.jpg" },
|
||
|
{
|
||
|
_name: "enclosure",
|
||
|
_attrs: {
|
||
|
url: "http://example.com/podcast.m4a",
|
||
|
length: "8727310",
|
||
|
type: "audio/x-m4a",
|
||
|
},
|
||
|
},
|
||
|
{ guid: "http://example.com/archive/aae20050615.m4a" },
|
||
|
{ pubDate: "Wed, 15 Jun 2011 19:00:00 GMT" },
|
||
|
{ "itunes:duration": "7:04" },
|
||
|
{ "itunes:keywords": "salt, pepper, shaker, exciting" },
|
||
|
],
|
||
|
},
|
||
|
{
|
||
|
item: [
|
||
|
{ title: "Podcast2 Title" },
|
||
|
{ "itunes:author": "Author2" },
|
||
|
{ "itunes:subtitle": "Subtitle2" },
|
||
|
{ "itunes:summary": "Summary2" },
|
||
|
{ "itunes:image": "image2.jpg" },
|
||
|
{
|
||
|
_name: "enclosure",
|
||
|
_attrs: {
|
||
|
url: "http://example.com/podcast2.m4a",
|
||
|
length: "655555",
|
||
|
type: "audio/x-m4a",
|
||
|
},
|
||
|
},
|
||
|
{ guid: "http://example.com/archive/aae2.m4a" },
|
||
|
{ pubDate: "Wed, 15 Jul 2011 19:00:00 GMT" },
|
||
|
{ "itunes:duration": "11:20" },
|
||
|
{ "itunes:keywords": "foo, bar" },
|
||
|
],
|
||
|
},
|
||
|
],
|
||
|
},
|
||
|
};
|
||
|
const config = {
|
||
|
header: true,
|
||
|
indent: " ",
|
||
|
};
|
||
|
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult = `<?xml version="1.0" encoding="UTF-8"?>
|
||
|
<rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0">
|
||
|
<channel>
|
||
|
<title>Title</title>
|
||
|
<link>google.com</link>
|
||
|
<language>en-us</language>
|
||
|
<copyright>Copyright 2011</copyright>
|
||
|
<itunes:subtitle>Subtitle</itunes:subtitle>
|
||
|
<itunes:author>Author</itunes:author>
|
||
|
<itunes:summary>Summary</itunes:summary>
|
||
|
<description>Description</description>
|
||
|
<itunes:owner>
|
||
|
<itunes:name>Name</itunes:name>
|
||
|
<itunes:email>Email</itunes:email>
|
||
|
</itunes:owner>
|
||
|
<itunes:image href="image.jpg"/>
|
||
|
<itunes:category text="Technology">
|
||
|
<itunes:category text="Gadgets"/>
|
||
|
</itunes:category>
|
||
|
<itunes:category text="TV & Film"/>
|
||
|
<item>
|
||
|
<title>Podcast Title</title>
|
||
|
<itunes:author>Author</itunes:author>
|
||
|
<itunes:subtitle>Subtitle</itunes:subtitle>
|
||
|
<itunes:summary>Summary</itunes:summary>
|
||
|
<itunes:image>image.jpg</itunes:image>
|
||
|
<enclosure url="http://example.com/podcast.m4a" length="8727310" type="audio/x-m4a"/>
|
||
|
<guid>http://example.com/archive/aae20050615.m4a</guid>
|
||
|
<pubDate>Wed, 15 Jun 2011 19:00:00 GMT</pubDate>
|
||
|
<itunes:duration>7:04</itunes:duration>
|
||
|
<itunes:keywords>salt, pepper, shaker, exciting</itunes:keywords>
|
||
|
</item>
|
||
|
<item>
|
||
|
<title>Podcast2 Title</title>
|
||
|
<itunes:author>Author2</itunes:author>
|
||
|
<itunes:subtitle>Subtitle2</itunes:subtitle>
|
||
|
<itunes:summary>Summary2</itunes:summary>
|
||
|
<itunes:image>image2.jpg</itunes:image>
|
||
|
<enclosure url="http://example.com/podcast2.m4a" length="655555" type="audio/x-m4a"/>
|
||
|
<guid>http://example.com/archive/aae2.m4a</guid>
|
||
|
<pubDate>Wed, 15 Jul 2011 19:00:00 GMT</pubDate>
|
||
|
<itunes:duration>11:20</itunes:duration>
|
||
|
<itunes:keywords>foo, bar</itunes:keywords>
|
||
|
</item>
|
||
|
</channel>
|
||
|
</rss>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("11 filter", () => {
|
||
|
const val = {
|
||
|
foo: "<a>",
|
||
|
bar: '"b"',
|
||
|
baz: "'&whee'",
|
||
|
};
|
||
|
const config = {
|
||
|
filter: {
|
||
|
"<": "<",
|
||
|
">": ">",
|
||
|
'"': """,
|
||
|
"'": "'",
|
||
|
"&": "&",
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult =
|
||
|
"<foo><a></foo><bar>"b"</bar><baz>'&whee'</baz>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("11b attributes filter", () => {
|
||
|
const val = {
|
||
|
_name: "foo",
|
||
|
_content: "bar",
|
||
|
_attrs: {
|
||
|
a: "http://example.com/?test='1'&foo=<bar>&whee=\"sha\"",
|
||
|
b: "http://example2.com/?test='2'&md=<5>&sum=\"sha\"",
|
||
|
},
|
||
|
};
|
||
|
const config = {
|
||
|
attributesFilter: {
|
||
|
"<": "<",
|
||
|
">": ">",
|
||
|
'"': """,
|
||
|
"'": "'",
|
||
|
"&": "&",
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult =
|
||
|
'<foo a="http://example.com/?test='1'&foo=<bar>&whee="sha"" b="http://example2.com/?test='2'&md=<5>&sum="sha"">bar</foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("12 avoiding self closing tags", () => {
|
||
|
const val = [
|
||
|
{
|
||
|
_name: "foo",
|
||
|
_content: "",
|
||
|
_selfCloseTag: false,
|
||
|
},
|
||
|
{
|
||
|
_name: "bar",
|
||
|
_content: undefined,
|
||
|
_selfCloseTag: false,
|
||
|
},
|
||
|
];
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<foo></foo><bar></bar>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("13 custom xml header", () => {
|
||
|
const val = {
|
||
|
foo: "bar",
|
||
|
};
|
||
|
const config = {
|
||
|
header: '<?xml version="1.0" encoding="UTF-16" standalone="yes"?>',
|
||
|
};
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult =
|
||
|
'<?xml version="1.0" encoding="UTF-16" standalone="yes"?><foo>bar</foo>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("14 emoji attributes", () => {
|
||
|
const val = {
|
||
|
html: {
|
||
|
_attrs: {
|
||
|
"⚡": true,
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<html ⚡/>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("15 duplicate attribute keys", () => {
|
||
|
const val = {
|
||
|
html: {
|
||
|
_attrs: [{ lang: "en" }, { lang: "klingon" }],
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = '<html lang="en" lang="klingon"/>';
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe("issues", () => {
|
||
|
it("issue #33: array of primitives", () => {
|
||
|
const val = {
|
||
|
x: [1, 2, 3],
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<x>1</x><x>2</x><x>3</x>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("issue #33: array of primitives 2", () => {
|
||
|
const val = {
|
||
|
a: {
|
||
|
x: [1, 2, 3],
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<a><x>1</x><x>2</x><x>3</x></a>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("issue #33: array of primitives 2 with indent", () => {
|
||
|
const val = {
|
||
|
a: {
|
||
|
x: [1, 2, 3],
|
||
|
},
|
||
|
};
|
||
|
const config = { indent: " " };
|
||
|
const result = toXML(val, config);
|
||
|
const expectedResult = "<a>\n <x>1</x>\n <x>2</x>\n <x>3</x>\n</a>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
it("issue #33: array of objects", () => {
|
||
|
const val = {
|
||
|
a: {
|
||
|
x: [
|
||
|
{ b: 1, c: 2 },
|
||
|
{ d: 3, e: 4 },
|
||
|
{ f: 5, g: 6 },
|
||
|
],
|
||
|
},
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult =
|
||
|
"<a><x><b>1</b><c>2</c><d>3</d><e>4</e><f>5</f><g>6</g></x></a>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
it("issue #33: array of objects jstoxml format", () => {
|
||
|
const val = {
|
||
|
a: [
|
||
|
{
|
||
|
_name: "foo",
|
||
|
_content: "1",
|
||
|
},
|
||
|
{
|
||
|
_name: "foo",
|
||
|
_content: "2",
|
||
|
},
|
||
|
],
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<a><foo>1</foo><foo>2</foo></a>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
it("issue #34: array of array", () => {
|
||
|
const val = {
|
||
|
Response: [
|
||
|
[
|
||
|
{
|
||
|
_name: "Play",
|
||
|
_content: "first sound",
|
||
|
},
|
||
|
{
|
||
|
_name: "Play",
|
||
|
_content: "second sound",
|
||
|
},
|
||
|
],
|
||
|
],
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult =
|
||
|
"<Response><Play>first sound</Play><Play>second sound</Play></Response>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
it("issue #34", () => {
|
||
|
const val = { t: [{ foo: "bar" }, { foo: "bar2" }] };
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<t><foo>bar</foo><foo>bar2</foo></t>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
it("issue #34", () => {
|
||
|
const val = {
|
||
|
t: [
|
||
|
{ _name: "foo", _content: "bar" },
|
||
|
{ _name: "foo", _content: "bar2" },
|
||
|
],
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = "<t><foo>bar</foo><foo>bar2</foo></t>";
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("issue #38", () => {
|
||
|
const getFooVal = (iteration) => iteration;
|
||
|
|
||
|
const getCurrentTime = (iterations) => {
|
||
|
return Array(iterations)
|
||
|
.fill(null)
|
||
|
.map((foo, index) => {
|
||
|
return {
|
||
|
currentTime: {
|
||
|
foo: getFooVal.bind(null, index + 1),
|
||
|
},
|
||
|
};
|
||
|
});
|
||
|
};
|
||
|
|
||
|
const val = {
|
||
|
invoice1: [
|
||
|
{
|
||
|
invoice: "a",
|
||
|
},
|
||
|
getCurrentTime.bind(null, 3),
|
||
|
{
|
||
|
foo2: "a",
|
||
|
},
|
||
|
],
|
||
|
};
|
||
|
const config = { indent: " " };
|
||
|
const result = toXML(val, config);
|
||
|
|
||
|
const expectedResult = `<invoice1>
|
||
|
<invoice>a</invoice>
|
||
|
<currentTime>
|
||
|
<foo>1</foo>
|
||
|
</currentTime>
|
||
|
<currentTime>
|
||
|
<foo>2</foo>
|
||
|
</currentTime>
|
||
|
<currentTime>
|
||
|
<foo>3</foo>
|
||
|
</currentTime>
|
||
|
<foo2>a</foo2>
|
||
|
</invoice1>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("issue #40 forced separator, no indent", () => {
|
||
|
const val = [{ a: "A Value" }, "\n", { b: "B Value" }];
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = `<a>A Value</a>
|
||
|
<b>B Value</b>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("issue #40 array with indent", () => {
|
||
|
const val = [{ a: "A Value" }, { b: "B Value" }];
|
||
|
const result = toXML(val, { indent: " " });
|
||
|
const expectedResult = `<a>A Value</a>
|
||
|
<b>B Value</b>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("issue #40 array without indent", () => {
|
||
|
const val = [{ a: "A Value" }, { b: "B Value" }];
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = `<a>A Value</a><b>B Value</b>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("issue #40 object with indent", () => {
|
||
|
const val = {
|
||
|
a: "A Value",
|
||
|
b: "B Value",
|
||
|
};
|
||
|
const result = toXML(val, { indent: " " });
|
||
|
const expectedResult = `<a>A Value</a>
|
||
|
<b>B Value</b>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("issue #40 object without indent", () => {
|
||
|
const val = {
|
||
|
a: "A Value",
|
||
|
b: "B Value",
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = `<a>A Value</a><b>B Value</b>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("comments 1", () => {
|
||
|
const val = {
|
||
|
_comment: "test comment",
|
||
|
a: "foo"
|
||
|
};
|
||
|
const result = toXML(val);
|
||
|
const expectedResult = `<!-- test comment --><a>foo</a>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("comments 2", () => {
|
||
|
const val = {
|
||
|
_comment: "test comment",
|
||
|
a: "foo"
|
||
|
};
|
||
|
const result = toXML(val, { indent: ' ' });
|
||
|
const expectedResult = `<!-- test comment -->
|
||
|
<a>foo</a>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("comments 3", () => {
|
||
|
const val = {
|
||
|
_comment: "comment 1",
|
||
|
b: {
|
||
|
_comment: "comment 2",
|
||
|
a: "foo"
|
||
|
}
|
||
|
};
|
||
|
const result = toXML(val, { indent: ' ' });
|
||
|
const expectedResult = `<!-- comment 1 -->
|
||
|
<b>
|
||
|
<!-- comment 2 -->
|
||
|
<a>foo</a>
|
||
|
</b>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("comments 4", () => {
|
||
|
const val = {
|
||
|
_comment: "comment 1",
|
||
|
b: [
|
||
|
{ _comment: "comment 2" },
|
||
|
{ _comment: "comment 3" },
|
||
|
{ a: "foo" }
|
||
|
]
|
||
|
};
|
||
|
const result = toXML(val, { indent: ' ' });
|
||
|
const expectedResult = `<!-- comment 1 -->
|
||
|
<b>
|
||
|
<!-- comment 2 -->
|
||
|
<!-- comment 3 -->
|
||
|
<a>foo</a>
|
||
|
</b>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it("comments 5", () => {
|
||
|
const val = {
|
||
|
_comment: 'Some important comment',
|
||
|
a: {
|
||
|
b: [1, 2, 3]
|
||
|
}
|
||
|
};
|
||
|
const result = toXML(val, { indent: ' ' });
|
||
|
const expectedResult = `<!-- Some important comment -->
|
||
|
<a>
|
||
|
<b>1</b>
|
||
|
<b>2</b>
|
||
|
<b>3</b>
|
||
|
</a>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
|
||
|
it("comments 6", () => {
|
||
|
const val = [
|
||
|
{ _comment: 'Some important comment' },
|
||
|
{ _comment: 'This is a very long comment!' },
|
||
|
{ _comment: 'More important exposition!' },
|
||
|
{ a: { b: [1, 2, 3] } }
|
||
|
];
|
||
|
const result = toXML(val, { indent: ' ' });
|
||
|
const expectedResult = `<!-- Some important comment -->
|
||
|
<!-- This is a very long comment! -->
|
||
|
<!-- More important exposition! -->
|
||
|
<a>
|
||
|
<b>1</b>
|
||
|
<b>2</b>
|
||
|
<b>3</b>
|
||
|
</a>`;
|
||
|
assert.equal(result, expectedResult);
|
||
|
});
|
||
|
});
|