import {
_CardGrid as CardGrid,
IntersectionObserver,
RecentSavesContainer,
OnboardingExperience,
DSSubHeader,
} from "content-src/components/DiscoveryStreamComponents/CardGrid/CardGrid";
import { combineReducers, createStore } from "redux";
import { INITIAL_STATE, reducers } from "common/Reducers.sys.mjs";
import { Provider } from "react-redux";
import {
DSCard,
PlaceholderDSCard,
} from "content-src/components/DiscoveryStreamComponents/DSCard/DSCard";
import { TopicsWidget } from "content-src/components/DiscoveryStreamComponents/TopicsWidget/TopicsWidget";
import {
actionCreators as ac,
actionTypes as at,
} from "common/Actions.sys.mjs";
import React from "react";
import { shallow, mount } from "enzyme";
// Wrap this around any component that uses useSelector,
// or any mount that uses a child that uses redux.
function WrapWithProvider({ children, state = INITIAL_STATE }) {
let store = createStore(combineReducers(reducers), state);
return {children};
}
describe("", () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(
);
});
it("should render an empty div", () => {
assert.ok(wrapper.exists());
assert.lengthOf(wrapper.children(), 0);
});
it("should render DSCards", () => {
wrapper.setProps({ items: 2, data: { recommendations: [{}, {}] } });
assert.lengthOf(wrapper.find(".ds-card-grid").children(), 2);
assert.equal(wrapper.find(".ds-card-grid").children().at(0).type(), DSCard);
});
it("should add 4 card classname to card grid", () => {
wrapper.setProps({
fourCardLayout: true,
data: { recommendations: [{}, {}] },
});
assert.ok(wrapper.find(".ds-card-grid-four-card-variant").exists());
});
it("should add no description classname to card grid", () => {
wrapper.setProps({
hideCardBackground: true,
data: { recommendations: [{}, {}] },
});
assert.ok(wrapper.find(".ds-card-grid-hide-background").exists());
});
it("should render sub header in the middle of the card grid for both regular and compact", () => {
const commonProps = {
essentialReadsHeader: true,
editorsPicksHeader: true,
items: 12,
data: {
recommendations: [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
},
Prefs: INITIAL_STATE.Prefs,
DiscoveryStream: INITIAL_STATE.DiscoveryStream,
};
wrapper = mount(
);
assert.ok(wrapper.find(DSSubHeader).exists());
wrapper.setProps({
compact: true,
});
wrapper = mount(
);
assert.ok(wrapper.find(DSSubHeader).exists());
});
it("should add/hide description classname to card grid", () => {
wrapper.setProps({
data: { recommendations: [{}, {}] },
});
assert.ok(wrapper.find(".ds-card-grid-include-descriptions").exists());
wrapper.setProps({
hideDescriptions: true,
data: { recommendations: [{}, {}] },
});
assert.ok(!wrapper.find(".ds-card-grid-include-descriptions").exists());
});
it("should create a widget card", () => {
wrapper.setProps({
widgets: {
positions: [{ index: 1 }],
data: [{ type: "TopicsWidget" }],
},
data: {
recommendations: [{}, {}, {}],
},
});
assert.ok(wrapper.find(TopicsWidget).exists());
});
});
// Build IntersectionObserver class with the arg `entries` for the intersect callback.
function buildIntersectionObserver(entries) {
return class {
constructor(callback) {
this.callback = callback;
}
observe() {
this.callback(entries);
}
unobserve() {}
disconnect() {}
};
}
describe("", () => {
let wrapper;
let fakeWindow;
let intersectEntries;
beforeEach(() => {
intersectEntries = [{ isIntersecting: true }];
fakeWindow = {
IntersectionObserver: buildIntersectionObserver(intersectEntries),
};
wrapper = mount();
});
it("should render an empty div", () => {
assert.ok(wrapper.exists());
assert.equal(wrapper.children().at(0).type(), "div");
});
it("should fire onIntersecting", () => {
const onIntersecting = sinon.stub();
wrapper = mount(
);
assert.calledOnce(onIntersecting);
});
});
describe("", () => {
let wrapper;
let fakeWindow;
let intersectEntries;
let dispatch;
beforeEach(() => {
dispatch = sinon.stub();
intersectEntries = [{ isIntersecting: true }];
fakeWindow = {
IntersectionObserver: buildIntersectionObserver(intersectEntries),
};
wrapper = mount(
).find(RecentSavesContainer);
});
it("should render an IntersectionObserver when not visible", () => {
intersectEntries = [{ isIntersecting: false }];
fakeWindow = {
IntersectionObserver: buildIntersectionObserver(intersectEntries),
};
wrapper = mount(
).find(RecentSavesContainer);
assert.ok(wrapper.exists());
assert.ok(wrapper.find(IntersectionObserver).exists());
});
it("should render nothing if visible until we log in", () => {
assert.ok(!wrapper.find(IntersectionObserver).exists());
assert.calledOnce(dispatch);
assert.calledWith(
dispatch,
ac.AlsoToMain({
type: at.DISCOVERY_STREAM_POCKET_STATE_INIT,
})
);
});
it("should render a grid if visible and logged in", () => {
assert.lengthOf(wrapper.find(".ds-card-grid"), 1);
assert.lengthOf(wrapper.find(DSSubHeader), 1);
assert.lengthOf(wrapper.find(PlaceholderDSCard), 2);
assert.lengthOf(wrapper.find(DSCard), 3);
});
it("should render a my list link with proper utm params", () => {
assert.equal(
wrapper.find(".section-sub-link").at(0).prop("url"),
"https://getpocket.com/a?utm_source=utmSource&utm_content=utmContent&utm_campaign=utmCampaign"
);
});
it("should fire a UserEvent for my list clicks", () => {
wrapper.find(".section-sub-link").at(0).simulate("click");
assert.calledWith(
dispatch,
ac.DiscoveryStreamUserEvent({
event: "CLICK",
source: `CARDGRID_RECENT_SAVES_VIEW_LIST`,
})
);
});
});
describe("", () => {
let wrapper;
let fakeWindow;
let intersectEntries;
let dispatch;
let resizeCallback;
let fakeResizeObserver = class {
constructor(callback) {
resizeCallback = callback;
}
observe() {}
unobserve() {}
disconnect() {}
};
beforeEach(() => {
dispatch = sinon.stub();
intersectEntries = [{ isIntersecting: true, intersectionRatio: 1 }];
fakeWindow = {
ResizeObserver: fakeResizeObserver,
IntersectionObserver: buildIntersectionObserver(intersectEntries),
document: {
visibilityState: "visible",
addEventListener: () => {},
removeEventListener: () => {},
},
};
wrapper = mount(
).find(OnboardingExperience);
});
it("should render a ds-onboarding", () => {
assert.ok(wrapper.exists());
assert.lengthOf(wrapper.find(".ds-onboarding"), 1);
});
it("should dismiss on dismiss click", () => {
wrapper.find(".ds-dismiss-button").simulate("click");
assert.calledWith(
dispatch,
ac.DiscoveryStreamUserEvent({
event: "BLOCK",
source: "POCKET_ONBOARDING",
})
);
assert.calledWith(
dispatch,
ac.SetPref("discoverystream.onboardingExperience.dismissed", true)
);
assert.equal(wrapper.getDOMNode().style["max-height"], "0px");
assert.equal(wrapper.getDOMNode().style.opacity, "0");
});
it("should update max-height on resize", () => {
sinon
.stub(wrapper.find(".ds-onboarding-ref").getDOMNode(), "offsetHeight")
.get(() => 123);
resizeCallback();
assert.equal(wrapper.getDOMNode().style["max-height"], "123px");
});
it("should fire intersection events", () => {
assert.calledWith(
dispatch,
ac.DiscoveryStreamUserEvent({
event: "IMPRESSION",
source: "POCKET_ONBOARDING",
})
);
});
});