Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/components/SectionCampaign/SectionCampaign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ import { JSONResult } from "@nosto/nosto-js/client"
*
* @property {string} placement - The placement identifier for the campaign.
* @property {string} section - The section to be used for Section Rendering API based rendering.
* @property {string} [titleSelector] - CSS selector for the title element to inject the campaign title (attribute: "title-selector").
*/
@customElement("nosto-section-campaign")
export class SectionCampaign extends NostoElement {
@property(String) placement!: string
@property(String) section!: string
@property(String) titleSelector?: string

async connectedCallback() {
this.toggleAttribute("loading", true)
Expand Down Expand Up @@ -56,8 +58,8 @@ export class SectionCampaign extends NostoElement {
// Check if nosto-section-campaign element exists in the section body
const nostoSectionCampaign = doc.body.querySelector(`nosto-section-campaign[placement="${this.placement}"]`)
const targetElement = nostoSectionCampaign || doc.body.firstElementChild
if (rec.title && targetElement) {
const headingEl = targetElement.querySelector(".nosto-title")
if (rec.title && targetElement && this.titleSelector) {
const headingEl = targetElement.querySelector(this.titleSelector)
if (headingEl) {
headingEl.textContent = rec.title
}
Expand Down
65 changes: 59 additions & 6 deletions test/components/SectionCampaign/SectionCampaign.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe("SectionCampaign", () => {
expect(el.hasAttribute("loading")).toBe(false)
})

it("replaces title in element with nosto-title attribute", async () => {
it("does not replace title when title-selector is not provided", async () => {
const products = [{ handle: "product-a" }]
const { attributeProductClicksInCampaign, load } = mockNostoRecs({
placement1: { products, title: "Custom Title" }
Expand All @@ -68,8 +68,8 @@ describe("SectionCampaign", () => {
await el.connectedCallback()

expect(load).toHaveBeenCalled()
expect(el.innerHTML).toContain("Custom Title")
expect(el.innerHTML).not.toContain("Default Title")
expect(el.innerHTML).toContain("Default Title")
expect(el.innerHTML).not.toContain("Custom Title")
expect(attributeProductClicksInCampaign).toHaveBeenCalledWith(el, { products, title: "Custom Title" })
expect(el.hasAttribute("loading")).toBe(false)
})
Expand Down Expand Up @@ -144,7 +144,7 @@ describe("SectionCampaign", () => {
expect(el.hasAttribute("loading")).toBe(false)
})

it("replaces title in nested nosto-section-campaign element with nosto-title class", async () => {
it("does not replace title in nested nosto-section-campaign when title-selector is not provided", async () => {
const products = [{ handle: "product-a" }]
const { attributeProductClicksInCampaign, load } = mockNostoRecs({
placement1: { products, title: "Custom Title" }
Expand All @@ -163,8 +163,8 @@ describe("SectionCampaign", () => {
await el.connectedCallback()

expect(load).toHaveBeenCalled()
expect(el.innerHTML).toContain("Custom Title")
expect(el.innerHTML).not.toContain("Default Title")
expect(el.innerHTML).toContain("Default Title")
expect(el.innerHTML).not.toContain("Custom Title")
expect(attributeProductClicksInCampaign).toHaveBeenCalledWith(el, { products, title: "Custom Title" })
expect(el.hasAttribute("loading")).toBe(false)
})
Expand Down Expand Up @@ -213,4 +213,57 @@ describe("SectionCampaign", () => {
expect(attributeProductClicksInCampaign).toHaveBeenCalledWith(el, { products })
expect(el.hasAttribute("loading")).toBe(false)
})

it("uses custom title-selector when provided", async () => {
const products = [{ handle: "product-a" }]
const { attributeProductClicksInCampaign, load } = mockNostoRecs({
placement1: { products, title: "Custom Title" }
})

const sectionHTML = `<div class="wrapper"><h2 class="custom-heading">Default Title</h2><div class="inner">Rendered Section</div></div>`
addHandlers(
http.get("/search", () => {
return HttpResponse.text(`<section>${sectionHTML}</section>`)
})
)

const el = (
<nosto-section-campaign placement="placement1" section="featured-section" title-selector=".custom-heading" />
) as SectionCampaign
document.body.appendChild(el)

await el.connectedCallback()

expect(load).toHaveBeenCalled()
expect(el.innerHTML).toContain("Custom Title")
expect(el.innerHTML).not.toContain("Default Title")
expect(attributeProductClicksInCampaign).toHaveBeenCalledWith(el, { products, title: "Custom Title" })
expect(el.hasAttribute("loading")).toBe(false)
})

it("does not inject title when title-selector is not provided", async () => {
const products = [{ handle: "product-a" }]
const { attributeProductClicksInCampaign, load } = mockNostoRecs({
placement1: { products, title: "Custom Title" }
})

const sectionHTML = `<div class="wrapper"><h2 class="nosto-title">Default Title</h2><h3 class="custom-heading">Should Not Change</h3></div>`
addHandlers(
http.get("/search", () => {
return HttpResponse.text(`<section>${sectionHTML}</section>`)
})
)

const el = (<nosto-section-campaign placement="placement1" section="featured-section" />) as SectionCampaign
document.body.appendChild(el)

await el.connectedCallback()

expect(load).toHaveBeenCalled()
expect(el.innerHTML).toContain("Default Title")
expect(el.innerHTML).not.toContain("Custom Title")
expect(el.innerHTML).toContain("Should Not Change")
expect(attributeProductClicksInCampaign).toHaveBeenCalledWith(el, { products, title: "Custom Title" })
expect(el.hasAttribute("loading")).toBe(false)
})
})