import React from "react"; import { mount } from "enzyme"; import { Provider } from "react-redux"; import { INITIAL_STATE, reducers } from "common/Reducers.sys.mjs"; import { BriefingCard } from "content-src/components/DiscoveryStreamComponents/BriefingCard/BriefingCard"; import { SafeAnchor } from "content-src/components/DiscoveryStreamComponents/SafeAnchor/SafeAnchor"; import { ImpressionStats } from "content-src/components/DiscoveryStreamImpressionStats/ImpressionStats"; import { combineReducers, createStore } from "redux"; import { actionTypes as at } from "common/Actions.mjs"; const DEFAULT_PROPS = { sectionClassNames: "col-1-medium", headlines: [ { id: "headline-1", url: "https://example.com/1", title: "First Headline", publisher: "Publisher One", icon_src: "https://example.com/icon1.png", pos: 0, recommendation_id: "rec-1", section: "daily-brief", }, { id: "headline-2", url: "https://example.com/2", title: "Second Headline", publisher: "Publisher Two", icon_src: "https://example.com/icon2.png", pos: 1, recommendation_id: "rec-2", section: "daily-brief", }, { id: "headline-3", url: "https://example.com/3", title: "Third Headline", publisher: "Publisher Three", icon_src: "https://example.com/icon3.png", pos: 2, recommendation_id: "rec-3", section: "daily-brief", }, ], lastUpdated: Date.now(), selectedTopics: ["topic1", "topic2"], isFollowed: true, firstVisibleTimestamp: Date.now() - 5000, }; function WrapWithProvider({ children, state = INITIAL_STATE }) { let store = createStore(combineReducers(reducers), state); return {children}; } describe("", () => { let wrapper; let sandbox; let dispatch; let clock; beforeEach(() => { sandbox = sinon.createSandbox(); dispatch = sandbox.stub(); wrapper = mount( ); }); afterEach(() => { sandbox.restore(); if (clock) { clock.restore(); } }); it("should render with 3 headlines", () => { assert.ok(wrapper.exists()); assert.lengthOf(wrapper.find(".briefing-card-headline"), 3); }); it("should render headline with title, link, publisher, and icon", () => { const firstHeadline = wrapper.find(SafeAnchor).at(0); assert.equal(firstHeadline.prop("url"), "https://example.com/1"); const title = firstHeadline.find(".briefing-card-headline-title"); assert.equal(title.text(), "First Headline"); const source = firstHeadline.find(".briefing-card-headline-source"); assert.equal(source.text(), "Publisher One"); const publisherIcon = firstHeadline.find(".briefing-card-headline-icon"); assert.equal(publisherIcon.prop("src"), "https://example.com/icon1.png"); }); it("should dispatch BLOCK_URL and IMPRESSION_STATS on dismiss", () => { const store = createStore(combineReducers(reducers), INITIAL_STATE); sandbox.spy(store, "dispatch"); wrapper = mount( ); const dispatchCountBeforeDismiss = store.dispatch.callCount; wrapper.find("panel-item").simulate("click"); assert.equal(store.dispatch.callCount, dispatchCountBeforeDismiss + 2); const blockAction = store.dispatch.getCall( dispatchCountBeforeDismiss ).firstArg; assert.equal(blockAction.type, at.BLOCK_URL); assert.lengthOf(blockAction.data, 3); assert.equal(blockAction.source, "DAILY_BRIEFING"); assert.equal(blockAction.data[0].format, "daily-briefing"); const impressionAction = store.dispatch.getCall( dispatchCountBeforeDismiss + 1 ).firstArg; assert.equal(impressionAction.type, at.TELEMETRY_IMPRESSION_STATS); assert.equal(impressionAction.data.source, "DAILY_BRIEFING"); }); it("should hide card after dismiss", () => { assert.lengthOf(wrapper.find(".briefing-card"), 1); wrapper.find("panel-item").simulate("click"); wrapper.update(); assert.lengthOf(wrapper.find(".briefing-card"), 0); }); it("should apply sectionClassNames to briefing card", () => { const card = wrapper.find(".briefing-card"); assert.isTrue(card.hasClass("col-1-medium")); }); describe("timestamp", () => { beforeEach(() => { clock = sandbox.useFakeTimers( new Date("2024-03-20T10:30:00.000Z").getTime() ); }); afterEach(() => { if (clock) { clock.restore(); clock = null; } }); it("should show timestamp within 15 minutes", () => { const lastUpdated = new Date("2024-03-20T10:20:00.000Z").getTime(); wrapper = mount( ); assert.lengthOf(wrapper.find(".briefing-card-timestamp"), 1); }); it("should hide timestamp after 15 minutes", () => { const lastUpdated = new Date("2024-03-20T10:00:00.000Z").getTime(); wrapper = mount( ); assert.lengthOf(wrapper.find(".briefing-card-timestamp"), 0); }); }); describe("onLinkClick", () => { it("should dispatch DiscoveryStreamUserEvent on headline click", () => { const store = createStore(combineReducers(reducers), INITIAL_STATE); sandbox.spy(store, "dispatch"); wrapper = mount( ); const dispatchCountBeforeClick = store.dispatch.callCount; const firstHeadline = wrapper.find(SafeAnchor).at(0); firstHeadline.simulate("click"); assert.equal(store.dispatch.callCount, dispatchCountBeforeClick + 2); const openLinkAction = store.dispatch.getCall( dispatchCountBeforeClick ).firstArg; assert.equal(openLinkAction.type, at.OPEN_LINK); const userEventAction = store.dispatch.getCall( dispatchCountBeforeClick + 1 ).firstArg; assert.equal(userEventAction.type, at.DISCOVERY_STREAM_USER_EVENT); assert.equal(userEventAction.data.value.format, "daily-briefing"); }); }); describe("ImpressionStats", () => { it("should render ImpressionStats component with correct props", () => { const impressionStats = wrapper.find(ImpressionStats); assert.lengthOf(impressionStats, 1); assert.equal(impressionStats.prop("source"), "DAILY_BRIEFING"); assert.lengthOf(impressionStats.prop("rows"), 3); }); it("should pass correct format to ImpressionStats rows", () => { const impressionStats = wrapper.find(ImpressionStats); const rows = impressionStats.prop("rows"); rows.forEach(row => { assert.equal(row.format, "daily-briefing"); }); }); }); });