tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TopSiteImpressionWrapper.test.jsx (4557B)


      1 import {
      2  TopSiteImpressionWrapper,
      3  INTERSECTION_RATIO,
      4 } from "content-src/components/TopSites/TopSiteImpressionWrapper";
      5 import { actionTypes as at } from "common/Actions.mjs";
      6 import React from "react";
      7 import { shallow } from "enzyme";
      8 
      9 describe("<TopSiteImpressionWrapper>", () => {
     10  const FullIntersectEntries = [
     11    { isIntersecting: true, intersectionRatio: INTERSECTION_RATIO },
     12  ];
     13  const ZeroIntersectEntries = [
     14    { isIntersecting: false, intersectionRatio: 0 },
     15  ];
     16  const PartialIntersectEntries = [
     17    { isIntersecting: true, intersectionRatio: INTERSECTION_RATIO / 2 },
     18  ];
     19 
     20  // Build IntersectionObserver class with the arg `entries` for the intersect callback.
     21  function buildIntersectionObserver(entries) {
     22    return class {
     23      constructor(callback) {
     24        this.callback = callback;
     25      }
     26 
     27      observe() {
     28        this.callback(entries);
     29      }
     30 
     31      unobserve() {}
     32    };
     33  }
     34 
     35  const DEFAULT_PROPS = {
     36    actionType: at.TOP_SITES_SPONSORED_IMPRESSION_STATS,
     37    tile: {
     38      tile_id: 1,
     39      position: 1,
     40      reporting_url: "https://test.reporting.com",
     41      advertiser: "test_advertiser",
     42    },
     43    IntersectionObserver: buildIntersectionObserver(FullIntersectEntries),
     44    document: {
     45      visibilityState: "visible",
     46      addEventListener: sinon.stub(),
     47      removeEventListener: sinon.stub(),
     48    },
     49  };
     50 
     51  const InnerEl = () => <div>Inner Element</div>;
     52 
     53  function renderTopSiteImpressionWrapper(props = {}) {
     54    return shallow(
     55      <TopSiteImpressionWrapper {...DEFAULT_PROPS} {...props}>
     56        <InnerEl />
     57      </TopSiteImpressionWrapper>
     58    );
     59  }
     60 
     61  it("should render props.children", () => {
     62    const wrapper = renderTopSiteImpressionWrapper();
     63    assert.ok(wrapper.contains(<InnerEl />));
     64  });
     65  it("should not send impression when the wrapped item is visbible but below the ratio", () => {
     66    const dispatch = sinon.spy();
     67    const props = {
     68      dispatch,
     69      IntersectionObserver: buildIntersectionObserver(PartialIntersectEntries),
     70    };
     71    renderTopSiteImpressionWrapper(props);
     72 
     73    assert.notCalled(dispatch);
     74  });
     75  it("should send an impression when the page is visible and the wrapped item meets the visibility ratio", () => {
     76    const dispatch = sinon.spy();
     77    const props = {
     78      dispatch,
     79      IntersectionObserver: buildIntersectionObserver(FullIntersectEntries),
     80    };
     81    renderTopSiteImpressionWrapper(props);
     82 
     83    assert.calledOnce(dispatch);
     84 
     85    let [action] = dispatch.firstCall.args;
     86    assert.equal(action.type, at.TOP_SITES_SPONSORED_IMPRESSION_STATS);
     87    assert.deepEqual(action.data, {
     88      type: "impression",
     89      ...DEFAULT_PROPS.tile,
     90    });
     91  });
     92  it("should send an impression when the wrapped item transiting from invisible to visible", () => {
     93    const dispatch = sinon.spy();
     94    const props = {
     95      dispatch,
     96      IntersectionObserver: buildIntersectionObserver(ZeroIntersectEntries),
     97    };
     98    const wrapper = renderTopSiteImpressionWrapper(props);
     99 
    100    assert.notCalled(dispatch);
    101 
    102    dispatch.resetHistory();
    103    wrapper.instance().impressionObserver.callback(FullIntersectEntries);
    104 
    105    // For the impression
    106    assert.calledOnce(dispatch);
    107 
    108    const [action] = dispatch.firstCall.args;
    109    assert.equal(action.type, at.TOP_SITES_SPONSORED_IMPRESSION_STATS);
    110    assert.deepEqual(action.data, {
    111      type: "impression",
    112      ...DEFAULT_PROPS.tile,
    113    });
    114  });
    115  it("should remove visibility change listener when the wrapper is removed", () => {
    116    const props = {
    117      dispatch: sinon.spy(),
    118      document: {
    119        visibilityState: "hidden",
    120        addEventListener: sinon.spy(),
    121        removeEventListener: sinon.spy(),
    122      },
    123      IntersectionObserver,
    124    };
    125 
    126    const wrapper = renderTopSiteImpressionWrapper(props);
    127    assert.calledWith(props.document.addEventListener, "visibilitychange");
    128    const [, listener] = props.document.addEventListener.firstCall.args;
    129 
    130    wrapper.unmount();
    131    assert.calledWith(
    132      props.document.removeEventListener,
    133      "visibilitychange",
    134      listener
    135    );
    136  });
    137  it("should unobserve the intersection observer when the wrapper is removed", () => {
    138    // eslint-disable-next-line no-shadow
    139    const IntersectionObserver =
    140      buildIntersectionObserver(ZeroIntersectEntries);
    141    const spy = sinon.spy(IntersectionObserver.prototype, "unobserve");
    142    const props = { dispatch: sinon.spy(), IntersectionObserver };
    143 
    144    const wrapper = renderTopSiteImpressionWrapper(props);
    145    wrapper.unmount();
    146 
    147    assert.calledOnce(spy);
    148  });
    149 });