import { actionCreators as ac, actionTypes as at, } from "common/Actions.sys.mjs"; import { ComponentPerfTimer } from "content-src/components/ComponentPerfTimer/ComponentPerfTimer"; import createMockRaf from "mock-raf"; import React from "react"; import { shallow } from "enzyme"; const perfSvc = { mark() {}, getMostRecentAbsMarkStartByName() {}, }; let DEFAULT_PROPS = { initialized: true, rows: [], id: "highlights", dispatch() {}, perfSvc, }; describe("", () => { let mockRaf; let sandbox; let wrapper; const InnerEl = () =>
Inner Element
; beforeEach(() => { mockRaf = createMockRaf(); sandbox = sinon.createSandbox(); sandbox.stub(window, "requestAnimationFrame").callsFake(mockRaf.raf); wrapper = shallow( ); }); afterEach(() => { sandbox.restore(); }); it("should render props.children", () => { assert.ok(wrapper.contains()); }); describe("#constructor", () => { beforeEach(() => { sandbox.stub(ComponentPerfTimer.prototype, "_maybeSendBadStateEvent"); sandbox.stub( ComponentPerfTimer.prototype, "_ensureFirstRenderTsRecorded" ); wrapper = shallow( , { disableLifecycleMethods: true } ); }); it("should have the correct defaults", () => { const instance = wrapper.instance(); assert.isFalse(instance._reportMissingData); assert.isFalse(instance._timestampHandled); assert.isFalse(instance._recordedFirstRender); }); }); describe("#render", () => { beforeEach(() => { sandbox.stub(DEFAULT_PROPS, "id").value("fake_section"); sandbox.stub(ComponentPerfTimer.prototype, "_maybeSendBadStateEvent"); sandbox.stub( ComponentPerfTimer.prototype, "_ensureFirstRenderTsRecorded" ); wrapper = shallow( ); }); it("should not call telemetry on sections that we don't want to record", () => { const instance = wrapper.instance(); assert.notCalled(instance._maybeSendBadStateEvent); assert.notCalled(instance._ensureFirstRenderTsRecorded); }); }); describe("#_componentDidMount", () => { it("should call _maybeSendPaintedEvent", () => { const instance = wrapper.instance(); const stub = sandbox.stub(instance, "_maybeSendPaintedEvent"); instance.componentDidMount(); assert.calledOnce(stub); }); it("should not call _maybeSendPaintedEvent if id not in RECORDED_SECTIONS", () => { sandbox.stub(DEFAULT_PROPS, "id").value("topstories"); wrapper = shallow( ); const instance = wrapper.instance(); const stub = sandbox.stub(instance, "_maybeSendPaintedEvent"); instance.componentDidMount(); assert.notCalled(stub); }); }); describe("#_componentDidUpdate", () => { it("should call _maybeSendPaintedEvent", () => { const instance = wrapper.instance(); const maybeSendPaintStub = sandbox.stub( instance, "_maybeSendPaintedEvent" ); instance.componentDidUpdate(); assert.calledOnce(maybeSendPaintStub); }); it("should not call _maybeSendPaintedEvent if id not in RECORDED_SECTIONS", () => { sandbox.stub(DEFAULT_PROPS, "id").value("topstories"); wrapper = shallow( ); const instance = wrapper.instance(); const stub = sandbox.stub(instance, "_maybeSendPaintedEvent"); instance.componentDidUpdate(); assert.notCalled(stub); }); }); describe("_ensureFirstRenderTsRecorded", () => { let recordFirstRenderStub; beforeEach(() => { sandbox.stub(ComponentPerfTimer.prototype, "_maybeSendBadStateEvent"); recordFirstRenderStub = sandbox.stub( ComponentPerfTimer.prototype, "_ensureFirstRenderTsRecorded" ); }); it("should set _recordedFirstRender", () => { sandbox.stub(DEFAULT_PROPS, "initialized").value(false); wrapper = shallow( ); const instance = wrapper.instance(); assert.isFalse(instance._recordedFirstRender); recordFirstRenderStub.callThrough(); instance._ensureFirstRenderTsRecorded(); assert.isTrue(instance._recordedFirstRender); }); it("should mark first_render_ts", () => { sandbox.stub(DEFAULT_PROPS, "initialized").value(false); wrapper = shallow( ); const instance = wrapper.instance(); const stub = sandbox.stub(perfSvc, "mark"); recordFirstRenderStub.callThrough(); instance._ensureFirstRenderTsRecorded(); assert.calledOnce(stub); assert.calledWithExactly(stub, `${DEFAULT_PROPS.id}_first_render_ts`); }); }); describe("#_maybeSendBadStateEvent", () => { let sendBadStateStub; beforeEach(() => { sendBadStateStub = sandbox.stub( ComponentPerfTimer.prototype, "_maybeSendBadStateEvent" ); sandbox.stub( ComponentPerfTimer.prototype, "_ensureFirstRenderTsRecorded" ); }); it("should set this._reportMissingData=true when called with initialized === false", () => { sandbox.stub(DEFAULT_PROPS, "initialized").value(false); wrapper = shallow( ); const instance = wrapper.instance(); assert.isFalse(instance._reportMissingData); sendBadStateStub.callThrough(); instance._maybeSendBadStateEvent(); assert.isTrue(instance._reportMissingData); }); it("should call _sendBadStateEvent if initialized & other metrics have been recorded", () => { const instance = wrapper.instance(); const stub = sandbox.stub(instance, "_sendBadStateEvent"); instance._reportMissingData = true; instance._timestampHandled = true; instance._recordedFirstRender = true; sendBadStateStub.callThrough(); instance._maybeSendBadStateEvent(); assert.calledOnce(stub); assert.isFalse(instance._reportMissingData); }); }); describe("#_maybeSendPaintedEvent", () => { it("should call _sendPaintedEvent if props.initialized is true", () => { sandbox.stub(DEFAULT_PROPS, "initialized").value(true); wrapper = shallow( , { disableLifecycleMethods: true } ); const instance = wrapper.instance(); const stub = sandbox.stub(instance, "_afterFramePaint"); assert.isFalse(instance._timestampHandled); instance._maybeSendPaintedEvent(); assert.calledOnce(stub); assert.calledWithExactly(stub, instance._sendPaintedEvent); assert.isTrue(wrapper.instance()._timestampHandled); }); it("should not call _sendPaintedEvent if this._timestampHandled is true", () => { const instance = wrapper.instance(); const spy = sinon.spy(instance, "_afterFramePaint"); instance._timestampHandled = true; instance._maybeSendPaintedEvent(); spy.neverCalledWith(instance._sendPaintedEvent); }); it("should not call _sendPaintedEvent if component not initialized", () => { sandbox.stub(DEFAULT_PROPS, "initialized").value(false); wrapper = shallow( ); const instance = wrapper.instance(); const spy = sinon.spy(instance, "_afterFramePaint"); instance._maybeSendPaintedEvent(); spy.neverCalledWith(instance._sendPaintedEvent); }); }); describe("#_afterFramePaint", () => { it("should call callback after the requestAnimationFrame callback returns", () => new Promise(resolve => { // Setting the callback to resolve is the test that it does finally get // called at the correct time, after the event loop ticks again. // If it doesn't get called, this test will time out. const callback = sandbox.spy(resolve); const instance = wrapper.instance(); instance._afterFramePaint(callback); assert.notCalled(callback); mockRaf.step({ count: 1 }); })); }); describe("#_sendBadStateEvent", () => { it("should call perfSvc.mark", () => { sandbox.spy(perfSvc, "mark"); const key = `${DEFAULT_PROPS.id}_data_ready_ts`; wrapper.instance()._sendBadStateEvent(); assert.calledOnce(perfSvc.mark); assert.calledWithExactly(perfSvc.mark, key); }); it("should call compute the delta from first render to data ready", () => { sandbox.stub(perfSvc, "getMostRecentAbsMarkStartByName"); wrapper .instance() ._sendBadStateEvent(`${DEFAULT_PROPS.id}_data_ready_ts`); assert.calledTwice(perfSvc.getMostRecentAbsMarkStartByName); assert.calledWithExactly( perfSvc.getMostRecentAbsMarkStartByName, `${DEFAULT_PROPS.id}_data_ready_ts` ); assert.calledWithExactly( perfSvc.getMostRecentAbsMarkStartByName, `${DEFAULT_PROPS.id}_first_render_ts` ); }); it("should call dispatch SAVE_SESSION_PERF_DATA", () => { sandbox .stub(perfSvc, "getMostRecentAbsMarkStartByName") .withArgs("highlights_first_render_ts") .returns(0.5) .withArgs("highlights_data_ready_ts") .returns(3.2); const dispatch = sandbox.spy(DEFAULT_PROPS, "dispatch"); wrapper = shallow( ); wrapper.instance()._sendBadStateEvent(); assert.calledOnce(dispatch); assert.calledWithExactly( dispatch, ac.OnlyToMain({ type: at.SAVE_SESSION_PERF_DATA, data: { [`${DEFAULT_PROPS.id}_data_late_by_ms`]: 2 }, }) ); }); }); describe("#_sendPaintedEvent", () => { beforeEach(() => { sandbox.stub(ComponentPerfTimer.prototype, "_maybeSendBadStateEvent"); sandbox.stub( ComponentPerfTimer.prototype, "_ensureFirstRenderTsRecorded" ); }); it("should not call mark with the wrong id", () => { sandbox.stub(perfSvc, "mark"); sandbox.stub(DEFAULT_PROPS, "id").value("fake_id"); wrapper = shallow( ); wrapper.instance()._sendPaintedEvent(); assert.notCalled(perfSvc.mark); }); it("should call mark with the correct topsites", () => { sandbox.stub(perfSvc, "mark"); sandbox.stub(DEFAULT_PROPS, "id").value("topsites"); wrapper = shallow( ); wrapper.instance()._sendPaintedEvent(); assert.calledOnce(perfSvc.mark); assert.calledWithExactly(perfSvc.mark, "topsites_first_painted_ts"); }); it("should not call getMostRecentAbsMarkStartByName if id!=topsites", () => { sandbox.stub(perfSvc, "getMostRecentAbsMarkStartByName"); sandbox.stub(DEFAULT_PROPS, "id").value("fake_id"); wrapper = shallow( ); wrapper.instance()._sendPaintedEvent(); assert.notCalled(perfSvc.getMostRecentAbsMarkStartByName); }); it("should call getMostRecentAbsMarkStartByName for topsites", () => { sandbox.stub(perfSvc, "getMostRecentAbsMarkStartByName"); sandbox.stub(DEFAULT_PROPS, "id").value("topsites"); wrapper = shallow( ); wrapper.instance()._sendPaintedEvent(); assert.calledOnce(perfSvc.getMostRecentAbsMarkStartByName); assert.calledWithExactly( perfSvc.getMostRecentAbsMarkStartByName, "topsites_first_painted_ts" ); }); it("should dispatch SAVE_SESSION_PERF_DATA", () => { sandbox.stub(perfSvc, "getMostRecentAbsMarkStartByName").returns(42); sandbox.stub(DEFAULT_PROPS, "id").value("topsites"); const dispatch = sandbox.spy(DEFAULT_PROPS, "dispatch"); wrapper = shallow( ); wrapper.instance()._sendPaintedEvent(); assert.calledOnce(dispatch); assert.calledWithExactly( dispatch, ac.OnlyToMain({ type: at.SAVE_SESSION_PERF_DATA, data: { topsites_first_painted_ts: 42 }, }) ); }); }); });