tor-browser

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

ComponentPerfTimer.test.jsx (13417B)


      1 import { actionCreators as ac, actionTypes as at } from "common/Actions.mjs";
      2 import { ComponentPerfTimer } from "content-src/components/ComponentPerfTimer/ComponentPerfTimer";
      3 import createMockRaf from "mock-raf";
      4 import React from "react";
      5 
      6 import { shallow } from "enzyme";
      7 
      8 const perfSvc = {
      9  mark() {},
     10  getMostRecentAbsMarkStartByName() {},
     11 };
     12 
     13 let DEFAULT_PROPS = {
     14  initialized: true,
     15  rows: [],
     16  id: "highlights",
     17  dispatch() {},
     18  perfSvc,
     19 };
     20 
     21 describe("<ComponentPerfTimer>", () => {
     22  let mockRaf;
     23  let sandbox;
     24  let wrapper;
     25 
     26  const InnerEl = () => <div>Inner Element</div>;
     27 
     28  beforeEach(() => {
     29    mockRaf = createMockRaf();
     30    sandbox = sinon.createSandbox();
     31    sandbox.stub(window, "requestAnimationFrame").callsFake(mockRaf.raf);
     32    wrapper = shallow(
     33      <ComponentPerfTimer {...DEFAULT_PROPS}>
     34        <InnerEl />
     35      </ComponentPerfTimer>
     36    );
     37  });
     38  afterEach(() => {
     39    sandbox.restore();
     40  });
     41 
     42  it("should render props.children", () => {
     43    assert.ok(wrapper.contains(<InnerEl />));
     44  });
     45 
     46  describe("#constructor", () => {
     47    beforeEach(() => {
     48      sandbox.stub(ComponentPerfTimer.prototype, "_maybeSendBadStateEvent");
     49      sandbox.stub(
     50        ComponentPerfTimer.prototype,
     51        "_ensureFirstRenderTsRecorded"
     52      );
     53      wrapper = shallow(
     54        <ComponentPerfTimer {...DEFAULT_PROPS}>
     55          <InnerEl />
     56        </ComponentPerfTimer>,
     57        { disableLifecycleMethods: true }
     58      );
     59    });
     60 
     61    it("should have the correct defaults", () => {
     62      const instance = wrapper.instance();
     63 
     64      assert.isFalse(instance._reportMissingData);
     65      assert.isFalse(instance._timestampHandled);
     66      assert.isFalse(instance._recordedFirstRender);
     67    });
     68  });
     69 
     70  describe("#render", () => {
     71    beforeEach(() => {
     72      sandbox.stub(DEFAULT_PROPS, "id").value("fake_section");
     73      sandbox.stub(ComponentPerfTimer.prototype, "_maybeSendBadStateEvent");
     74      sandbox.stub(
     75        ComponentPerfTimer.prototype,
     76        "_ensureFirstRenderTsRecorded"
     77      );
     78      wrapper = shallow(
     79        <ComponentPerfTimer {...DEFAULT_PROPS}>
     80          <InnerEl />
     81        </ComponentPerfTimer>
     82      );
     83    });
     84 
     85    it("should not call telemetry on sections that we don't want to record", () => {
     86      const instance = wrapper.instance();
     87 
     88      assert.notCalled(instance._maybeSendBadStateEvent);
     89      assert.notCalled(instance._ensureFirstRenderTsRecorded);
     90    });
     91  });
     92 
     93  describe("#_componentDidMount", () => {
     94    it("should call _maybeSendPaintedEvent", () => {
     95      const instance = wrapper.instance();
     96      const stub = sandbox.stub(instance, "_maybeSendPaintedEvent");
     97 
     98      instance.componentDidMount();
     99 
    100      assert.calledOnce(stub);
    101    });
    102 
    103    it("should not call _maybeSendPaintedEvent if id not in RECORDED_SECTIONS", () => {
    104      sandbox.stub(DEFAULT_PROPS, "id").value("topstories");
    105      wrapper = shallow(
    106        <ComponentPerfTimer {...DEFAULT_PROPS}>
    107          <InnerEl />
    108        </ComponentPerfTimer>
    109      );
    110      const instance = wrapper.instance();
    111      const stub = sandbox.stub(instance, "_maybeSendPaintedEvent");
    112 
    113      instance.componentDidMount();
    114 
    115      assert.notCalled(stub);
    116    });
    117  });
    118 
    119  describe("#_componentDidUpdate", () => {
    120    it("should call _maybeSendPaintedEvent", () => {
    121      const instance = wrapper.instance();
    122      const maybeSendPaintStub = sandbox.stub(
    123        instance,
    124        "_maybeSendPaintedEvent"
    125      );
    126 
    127      instance.componentDidUpdate();
    128 
    129      assert.calledOnce(maybeSendPaintStub);
    130    });
    131 
    132    it("should not call _maybeSendPaintedEvent if id not in RECORDED_SECTIONS", () => {
    133      sandbox.stub(DEFAULT_PROPS, "id").value("topstories");
    134      wrapper = shallow(
    135        <ComponentPerfTimer {...DEFAULT_PROPS}>
    136          <InnerEl />
    137        </ComponentPerfTimer>
    138      );
    139      const instance = wrapper.instance();
    140      const stub = sandbox.stub(instance, "_maybeSendPaintedEvent");
    141 
    142      instance.componentDidUpdate();
    143 
    144      assert.notCalled(stub);
    145    });
    146  });
    147 
    148  describe("_ensureFirstRenderTsRecorded", () => {
    149    let recordFirstRenderStub;
    150    beforeEach(() => {
    151      sandbox.stub(ComponentPerfTimer.prototype, "_maybeSendBadStateEvent");
    152      recordFirstRenderStub = sandbox.stub(
    153        ComponentPerfTimer.prototype,
    154        "_ensureFirstRenderTsRecorded"
    155      );
    156    });
    157 
    158    it("should set _recordedFirstRender", () => {
    159      sandbox.stub(DEFAULT_PROPS, "initialized").value(false);
    160      wrapper = shallow(
    161        <ComponentPerfTimer {...DEFAULT_PROPS}>
    162          <InnerEl />
    163        </ComponentPerfTimer>
    164      );
    165      const instance = wrapper.instance();
    166 
    167      assert.isFalse(instance._recordedFirstRender);
    168 
    169      recordFirstRenderStub.callThrough();
    170      instance._ensureFirstRenderTsRecorded();
    171 
    172      assert.isTrue(instance._recordedFirstRender);
    173    });
    174 
    175    it("should mark first_render_ts", () => {
    176      sandbox.stub(DEFAULT_PROPS, "initialized").value(false);
    177      wrapper = shallow(
    178        <ComponentPerfTimer {...DEFAULT_PROPS}>
    179          <InnerEl />
    180        </ComponentPerfTimer>
    181      );
    182      const instance = wrapper.instance();
    183      const stub = sandbox.stub(perfSvc, "mark");
    184 
    185      recordFirstRenderStub.callThrough();
    186      instance._ensureFirstRenderTsRecorded();
    187 
    188      assert.calledOnce(stub);
    189      assert.calledWithExactly(stub, `${DEFAULT_PROPS.id}_first_render_ts`);
    190    });
    191  });
    192 
    193  describe("#_maybeSendBadStateEvent", () => {
    194    let sendBadStateStub;
    195    beforeEach(() => {
    196      sendBadStateStub = sandbox.stub(
    197        ComponentPerfTimer.prototype,
    198        "_maybeSendBadStateEvent"
    199      );
    200      sandbox.stub(
    201        ComponentPerfTimer.prototype,
    202        "_ensureFirstRenderTsRecorded"
    203      );
    204    });
    205 
    206    it("should set this._reportMissingData=true when called with initialized === false", () => {
    207      sandbox.stub(DEFAULT_PROPS, "initialized").value(false);
    208      wrapper = shallow(
    209        <ComponentPerfTimer {...DEFAULT_PROPS}>
    210          <InnerEl />
    211        </ComponentPerfTimer>
    212      );
    213      const instance = wrapper.instance();
    214 
    215      assert.isFalse(instance._reportMissingData);
    216 
    217      sendBadStateStub.callThrough();
    218      instance._maybeSendBadStateEvent();
    219 
    220      assert.isTrue(instance._reportMissingData);
    221    });
    222 
    223    it("should call _sendBadStateEvent if initialized & other metrics have been recorded", () => {
    224      const instance = wrapper.instance();
    225      const stub = sandbox.stub(instance, "_sendBadStateEvent");
    226      instance._reportMissingData = true;
    227      instance._timestampHandled = true;
    228      instance._recordedFirstRender = true;
    229 
    230      sendBadStateStub.callThrough();
    231      instance._maybeSendBadStateEvent();
    232 
    233      assert.calledOnce(stub);
    234      assert.isFalse(instance._reportMissingData);
    235    });
    236  });
    237 
    238  describe("#_maybeSendPaintedEvent", () => {
    239    it("should call _sendPaintedEvent if props.initialized is true", () => {
    240      sandbox.stub(DEFAULT_PROPS, "initialized").value(true);
    241      wrapper = shallow(
    242        <ComponentPerfTimer {...DEFAULT_PROPS}>
    243          <InnerEl />
    244        </ComponentPerfTimer>,
    245        { disableLifecycleMethods: true }
    246      );
    247      const instance = wrapper.instance();
    248      const stub = sandbox.stub(instance, "_afterFramePaint");
    249 
    250      assert.isFalse(instance._timestampHandled);
    251 
    252      instance._maybeSendPaintedEvent();
    253 
    254      assert.calledOnce(stub);
    255      assert.calledWithExactly(stub, instance._sendPaintedEvent);
    256      assert.isTrue(wrapper.instance()._timestampHandled);
    257    });
    258    it("should not call _sendPaintedEvent if this._timestampHandled is true", () => {
    259      const instance = wrapper.instance();
    260      const spy = sinon.spy(instance, "_afterFramePaint");
    261      instance._timestampHandled = true;
    262 
    263      instance._maybeSendPaintedEvent();
    264      spy.neverCalledWith(instance._sendPaintedEvent);
    265    });
    266    it("should not call _sendPaintedEvent if component not initialized", () => {
    267      sandbox.stub(DEFAULT_PROPS, "initialized").value(false);
    268      wrapper = shallow(
    269        <ComponentPerfTimer {...DEFAULT_PROPS}>
    270          <InnerEl />
    271        </ComponentPerfTimer>
    272      );
    273      const instance = wrapper.instance();
    274      const spy = sinon.spy(instance, "_afterFramePaint");
    275 
    276      instance._maybeSendPaintedEvent();
    277 
    278      spy.neverCalledWith(instance._sendPaintedEvent);
    279    });
    280  });
    281 
    282  describe("#_afterFramePaint", () => {
    283    it("should call callback after the requestAnimationFrame callback returns", () =>
    284      new Promise(resolve => {
    285        // Setting the callback to resolve is the test that it does finally get
    286        // called at the correct time, after the event loop ticks again.
    287        // If it doesn't get called, this test will time out.
    288        const callback = sandbox.spy(resolve);
    289 
    290        const instance = wrapper.instance();
    291 
    292        instance._afterFramePaint(callback);
    293 
    294        assert.notCalled(callback);
    295        mockRaf.step({ count: 1 });
    296      }));
    297  });
    298 
    299  describe("#_sendBadStateEvent", () => {
    300    it("should call perfSvc.mark", () => {
    301      sandbox.spy(perfSvc, "mark");
    302      const key = `${DEFAULT_PROPS.id}_data_ready_ts`;
    303 
    304      wrapper.instance()._sendBadStateEvent();
    305 
    306      assert.calledOnce(perfSvc.mark);
    307      assert.calledWithExactly(perfSvc.mark, key);
    308    });
    309 
    310    it("should call compute the delta from first render to data ready", () => {
    311      sandbox.stub(perfSvc, "getMostRecentAbsMarkStartByName");
    312 
    313      wrapper
    314        .instance()
    315        ._sendBadStateEvent(`${DEFAULT_PROPS.id}_data_ready_ts`);
    316 
    317      assert.calledTwice(perfSvc.getMostRecentAbsMarkStartByName);
    318      assert.calledWithExactly(
    319        perfSvc.getMostRecentAbsMarkStartByName,
    320        `${DEFAULT_PROPS.id}_data_ready_ts`
    321      );
    322      assert.calledWithExactly(
    323        perfSvc.getMostRecentAbsMarkStartByName,
    324        `${DEFAULT_PROPS.id}_first_render_ts`
    325      );
    326    });
    327 
    328    it("should call dispatch SAVE_SESSION_PERF_DATA", () => {
    329      sandbox
    330        .stub(perfSvc, "getMostRecentAbsMarkStartByName")
    331        .withArgs("highlights_first_render_ts")
    332        .returns(0.5)
    333        .withArgs("highlights_data_ready_ts")
    334        .returns(3.2);
    335 
    336      const dispatch = sandbox.spy(DEFAULT_PROPS, "dispatch");
    337      wrapper = shallow(
    338        <ComponentPerfTimer {...DEFAULT_PROPS}>
    339          <InnerEl />
    340        </ComponentPerfTimer>
    341      );
    342 
    343      wrapper.instance()._sendBadStateEvent();
    344 
    345      assert.calledOnce(dispatch);
    346      assert.calledWithExactly(
    347        dispatch,
    348        ac.OnlyToMain({
    349          type: at.SAVE_SESSION_PERF_DATA,
    350          data: { [`${DEFAULT_PROPS.id}_data_late_by_ms`]: 2 },
    351        })
    352      );
    353    });
    354  });
    355 
    356  describe("#_sendPaintedEvent", () => {
    357    beforeEach(() => {
    358      sandbox.stub(ComponentPerfTimer.prototype, "_maybeSendBadStateEvent");
    359      sandbox.stub(
    360        ComponentPerfTimer.prototype,
    361        "_ensureFirstRenderTsRecorded"
    362      );
    363    });
    364 
    365    it("should not call mark with the wrong id", () => {
    366      sandbox.stub(perfSvc, "mark");
    367      sandbox.stub(DEFAULT_PROPS, "id").value("fake_id");
    368      wrapper = shallow(
    369        <ComponentPerfTimer {...DEFAULT_PROPS}>
    370          <InnerEl />
    371        </ComponentPerfTimer>
    372      );
    373 
    374      wrapper.instance()._sendPaintedEvent();
    375 
    376      assert.notCalled(perfSvc.mark);
    377    });
    378    it("should call mark with the correct topsites", () => {
    379      sandbox.stub(perfSvc, "mark");
    380      sandbox.stub(DEFAULT_PROPS, "id").value("topsites");
    381      wrapper = shallow(
    382        <ComponentPerfTimer {...DEFAULT_PROPS}>
    383          <InnerEl />
    384        </ComponentPerfTimer>
    385      );
    386 
    387      wrapper.instance()._sendPaintedEvent();
    388 
    389      assert.calledOnce(perfSvc.mark);
    390      assert.calledWithExactly(perfSvc.mark, "topsites_first_painted_ts");
    391    });
    392    it("should not call getMostRecentAbsMarkStartByName if id!=topsites", () => {
    393      sandbox.stub(perfSvc, "getMostRecentAbsMarkStartByName");
    394      sandbox.stub(DEFAULT_PROPS, "id").value("fake_id");
    395      wrapper = shallow(
    396        <ComponentPerfTimer {...DEFAULT_PROPS}>
    397          <InnerEl />
    398        </ComponentPerfTimer>
    399      );
    400 
    401      wrapper.instance()._sendPaintedEvent();
    402 
    403      assert.notCalled(perfSvc.getMostRecentAbsMarkStartByName);
    404    });
    405    it("should call getMostRecentAbsMarkStartByName for topsites", () => {
    406      sandbox.stub(perfSvc, "getMostRecentAbsMarkStartByName");
    407      sandbox.stub(DEFAULT_PROPS, "id").value("topsites");
    408      wrapper = shallow(
    409        <ComponentPerfTimer {...DEFAULT_PROPS}>
    410          <InnerEl />
    411        </ComponentPerfTimer>
    412      );
    413 
    414      wrapper.instance()._sendPaintedEvent();
    415 
    416      assert.calledOnce(perfSvc.getMostRecentAbsMarkStartByName);
    417      assert.calledWithExactly(
    418        perfSvc.getMostRecentAbsMarkStartByName,
    419        "topsites_first_painted_ts"
    420      );
    421    });
    422    it("should dispatch SAVE_SESSION_PERF_DATA", () => {
    423      sandbox.stub(perfSvc, "getMostRecentAbsMarkStartByName").returns(42);
    424      sandbox.stub(DEFAULT_PROPS, "id").value("topsites");
    425      const dispatch = sandbox.spy(DEFAULT_PROPS, "dispatch");
    426      wrapper = shallow(
    427        <ComponentPerfTimer {...DEFAULT_PROPS}>
    428          <InnerEl />
    429        </ComponentPerfTimer>
    430      );
    431 
    432      wrapper.instance()._sendPaintedEvent();
    433 
    434      assert.calledOnce(dispatch);
    435      assert.calledWithExactly(
    436        dispatch,
    437        ac.OnlyToMain({
    438          type: at.SAVE_SESSION_PERF_DATA,
    439          data: { topsites_first_painted_ts: 42 },
    440        })
    441      );
    442    });
    443  });
    444 });