From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../components/ComponentPerfTimer.test.jsx | 447 +++++++++++++++++++++ 1 file changed, 447 insertions(+) create mode 100644 browser/components/newtab/test/unit/content-src/components/ComponentPerfTimer.test.jsx (limited to 'browser/components/newtab/test/unit/content-src/components/ComponentPerfTimer.test.jsx') diff --git a/browser/components/newtab/test/unit/content-src/components/ComponentPerfTimer.test.jsx b/browser/components/newtab/test/unit/content-src/components/ComponentPerfTimer.test.jsx new file mode 100644 index 0000000000..baf203947e --- /dev/null +++ b/browser/components/newtab/test/unit/content-src/components/ComponentPerfTimer.test.jsx @@ -0,0 +1,447 @@ +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 }, + }) + ); + }); + }); +}); -- cgit v1.2.3