diff --git a/src/components/LuxMenuBar.vue b/src/components/LuxMenuBar.vue
index 4cccbfb..fbc4fe2 100644
--- a/src/components/LuxMenuBar.vue
+++ b/src/components/LuxMenuBar.vue
@@ -10,8 +10,8 @@
class="lux-has-children lux-nav-item"
aria-haspopup="true"
@click="menuItemClicked($event, item)"
- >{{ item.name }}
+ >
@@ -50,10 +50,11 @@
{ 'lux-disabled': item.disabled },
{ 'lux-is-child': item.hasOwnProperty('parent') === true },
]"
- v-html="item.name"
:disabled="item.disabled"
@click="menuItemClicked($event, item)"
- >
+ >
+
+
@@ -88,7 +89,7 @@
:data-method="item.method"
@click="setActiveItem(index)"
>
- {{ item.name }}
+
-
@@ -101,8 +102,8 @@
:data-method="child.method"
class="lux-nav-item"
@click="menuItemClicked(child)"
- >{{ child.name }}
+ >
@@ -115,7 +116,7 @@
class="lux-nav-item"
@click="menuItemClicked(item)"
>
- {{ item.name }}
+
@@ -125,6 +126,7 @@
+
+ ```jsx
+
+
+
+ ```
+ Security considerations:
+
+ - You can add any arbitrary HTML to the
unsafe_name
property,
+ and it will be rendered for the user. If you don't need to add arbitrary
+ HTML, use the name
property instead. Don't bind the
+ unsafe_name
property to any user-provided value, since it does
+ not have Cross-Site Scripting protections (name
does have these
+ protections).
+
+
+
diff --git a/tests/unit/specs/components/__snapshots__/luxMenuBar.spec.js.snap b/tests/unit/specs/components/__snapshots__/luxMenuBar.spec.js.snap
index d1a03dd..d131c30 100644
--- a/tests/unit/specs/components/__snapshots__/luxMenuBar.spec.js.snap
+++ b/tests/unit/specs/components/__snapshots__/luxMenuBar.spec.js.snap
@@ -14,7 +14,9 @@ exports[`LuxMenuBar.vue has the expected html structure 1`] = `
href="/example/"
title="Foo"
>
+
Foo
+
+
Bar
+
diff --git a/tests/unit/specs/components/luxMenuBar.spec.js b/tests/unit/specs/components/luxMenuBar.spec.js
index 7f27088..218d7d4 100644
--- a/tests/unit/specs/components/luxMenuBar.spec.js
+++ b/tests/unit/specs/components/luxMenuBar.spec.js
@@ -84,12 +84,26 @@ describe("LuxMenuBar.vue", () => {
expect(wrapper.get("nav").classes()).toContain("dark")
})
- it("has to a light theme", async () => {
+ it("has a light theme", async () => {
wrapper.setProps({ type: "main-menu", theme: "light" })
await nextTick()
expect(wrapper.get("nav").classes()).toContain("light")
})
+ it("can include arbitrary html with the unsafe_name property", async () => {
+ wrapper.setProps({
+ menuItems: [
+ {
+ name: "Foo Bar",
+ unsafe_name: "Foo Bar",
+ },
+ ],
+ })
+ await nextTick()
+ expect(wrapper.get("#my-foo").text()).toEqual("Foo")
+ expect(wrapper.get(".my-bar").text()).toEqual("Bar")
+ })
+
it("has the expected html structure", () => {
expect(wrapper.element).toMatchSnapshot()
})
diff --git a/tests/unit/specs/components/luxMenuBarLabel.spec.js b/tests/unit/specs/components/luxMenuBarLabel.spec.js
new file mode 100644
index 0000000..8f3ab10
--- /dev/null
+++ b/tests/unit/specs/components/luxMenuBarLabel.spec.js
@@ -0,0 +1,60 @@
+import { mount } from "@vue/test-utils"
+import _LuxMenuBarLabel from "@/components/_LuxMenuBarLabel.vue"
+
+describe("_LuxMenuBarLabel", () => {
+ let wrapper
+ describe("when item prop has a name", () => {
+ beforeEach(() => {
+ wrapper = mount(_LuxMenuBarLabel, {
+ props: {
+ item: { name: "Hello!" },
+ },
+ })
+ })
+ it("displays the name", () => {
+ expect(wrapper.text()).toEqual("Hello!")
+ })
+ })
+ describe("when item prop name contains HTML", () => {
+ beforeEach(() => {
+ wrapper = mount(_LuxMenuBarLabel, {
+ props: {
+ item: { name: '' },
+ },
+ })
+ })
+ it("escapes the HTML, so that it displays as text rather than being potentially unsafe", () => {
+ expect(wrapper.text()).toEqual('')
+ expect(wrapper.find("script").exists()).toBe(false)
+ })
+ })
+ describe("when item prop has an unsafe_name", () => {
+ beforeEach(() => {
+ wrapper = mount(_LuxMenuBarLabel, {
+ props: {
+ item: { unsafe_name: "Hello!" },
+ },
+ })
+ })
+ it("does not escape the HTML", () => {
+ expect(wrapper.text()).toEqual("Hello!")
+ expect(wrapper.find("span").exists()).toBe(true)
+ })
+ })
+ describe("when item prop has both a name and an unsafe_name", () => {
+ beforeEach(() => {
+ wrapper = mount(_LuxMenuBarLabel, {
+ props: {
+ item: {
+ name: "Goodbye",
+ unsafe_name: "Hello!",
+ },
+ },
+ })
+ })
+ it("uses the unsafe name", () => {
+ expect(wrapper.text()).toEqual("Hello!")
+ expect(wrapper.find("span").exists()).toBe(true)
+ })
+ })
+})