import { BenchmarkRunner } from "../resources/benchmark-runner.mjs"; import { defaultParams } from "../resources/params.mjs"; function TEST_FIXTURE(name) { return { name, run: sinon.stub(), }; } const SUITES_FIXTURE = [ { name: "Suite 1", tests: [TEST_FIXTURE("Test 1"), TEST_FIXTURE("Test 2"), TEST_FIXTURE("Test 3")], }, { name: "Suite 2", tests: [TEST_FIXTURE("Test 1")], }, ]; const CLIENT_FIXTURE = { willRunTest: sinon.stub(), didRunTest: sinon.stub(), didRunSuites: sinon.stub(), }; function stubPerformanceNowCalls(syncStart, syncEnd, asyncStart, asyncEnd) { sinon .stub(window.performance, "now") .onFirstCall() .returns(syncStart) // startTime (sync) .onSecondCall() .returns(syncEnd) // endTime (sync) .onThirdCall() .returns(asyncStart) // startTime (async) .returns(asyncEnd); // endTime (async) } describe("BenchmarkRunner", () => { const { spy, stub, assert } = sinon; let runner; before(() => { runner = new BenchmarkRunner(SUITES_FIXTURE, CLIENT_FIXTURE); }); it("should be defined", () => { expect(runner).not.to.be(undefined); }); describe("Frame", () => { describe("_removeFrame", () => { let frame, removeChildSpy; before(async () => { frame = await runner._appendFrame(); removeChildSpy = spy(frame.parentNode, "removeChild"); }); it("should remove the frame if a frame is defined", () => { expect(runner._frame).to.equal(frame); runner._removeFrame(); assert.calledWith(removeChildSpy, frame); expect(runner._frame).to.equal(null); }); }); describe("_appendFrame", () => { const DEFAULT_WIDTH = defaultParams.viewport.width; const DEFAULT_HEIGHT = defaultParams.viewport.height; it(`should create an absolutely positioned iframe with ${DEFAULT_WIDTH}px x ${DEFAULT_WIDTH}px dimensions`, async () => { const createElementSpy = spy(document, "createElement"); const frame = await runner._appendFrame(); expect(frame).to.be.a(HTMLIFrameElement); assert.calledWith(createElementSpy, frame.nodeName.toLowerCase()); const { width, height, position } = getComputedStyle(frame); expect(parseInt(width)).to.equal(DEFAULT_WIDTH); expect(parseInt(height)).to.equal(DEFAULT_HEIGHT); expect(position).to.be("absolute"); }); it("should disable scrolling in the frame", async () => { const { scrolling } = await runner._appendFrame(); expect(scrolling).to.be("no"); }); it("should insert the frame as the first child in the document body", async () => { const firstChild = document.createTextNode("First Child"); const insertBeforeSpy = spy(document.body, "insertBefore"); document.body.prepend(firstChild); const frame = await runner._appendFrame(); assert.calledWith(insertBeforeSpy, frame, firstChild); document.body.removeChild(firstChild); // clean up }); }); }); describe("Suite", () => { describe("_runAllSuites", () => { let _runSuiteStub, _finalizeStub, _removeFrameStub; before(async () => { _runSuiteStub = stub(runner, "_runSuite").callsFake(() => null); _finalizeStub = stub(runner, "_finalize").callsFake(() => null); _removeFrameStub = stub(runner, "_removeFrame").callsFake(() => null); await runner._runAllSuites(); }); it("should run all test suites", async () => { assert.calledTwice(_runSuiteStub); }); it("should remove the previous frame and then the current frame", () => { assert.calledTwice(_removeFrameStub); }); it("should fire the function responsible for finalizing results", () => { assert.calledOnce(_finalizeStub); }); }); describe("_runSuite", () => { let _prepareSuiteStub, _runTestAndRecordResultsStub, performanceMarkSpy; const suite = SUITES_FIXTURE[0]; before(async () => { _prepareSuiteStub = stub(runner, "_prepareSuite").callsFake(() => null); _runTestAndRecordResultsStub = stub(runner, "_runTestAndRecordResults").callsFake(() => null); performanceMarkSpy = spy(window.performance, "mark"); runner._runSuite(suite); }); it("should prepare the suite first", async () => { assert.calledOnce(_prepareSuiteStub); }); it("should run and record results for every test in suite", async () => { assert.calledThrice(_runTestAndRecordResultsStub); assert.calledWith(performanceMarkSpy, "suite-Suite 1-prepare-start"); assert.calledWith(performanceMarkSpy, "suite-Suite 1-prepare-end"); assert.calledWith(performanceMarkSpy, "suite-Suite 1-start"); assert.calledWith(performanceMarkSpy, "suite-Suite 1-end"); expect(performanceMarkSpy.callCount).to.equal(4); }); }); }); describe("Test", () => { describe("_runTestAndRecordResults", () => { let performanceMarkSpy; const suite = SUITES_FIXTURE[0]; before(async () => { await runner._appendFrame(); performanceMarkSpy = spy(window.performance, "mark"); await runner._runTestAndRecordResults(suite, suite.tests[0]); }); it("should run client pre and post hooks if present", () => { assert.calledWith(runner._client.willRunTest, suite, suite.tests[0]); assert.calledWith(runner._client.didRunTest, suite, suite.tests[0]); }); it("should write performance marks at the start and end of the test with the correct test name", () => { assert.calledWith(performanceMarkSpy, "Suite 1.Test 1-start"); assert.calledWith(performanceMarkSpy, "Suite 1.Test 1-sync-end"); assert.calledWith(performanceMarkSpy, "Suite 1.Test 1-async-start"); assert.calledWith(performanceMarkSpy, "Suite 1.Test 1-async-end"); expect(performanceMarkSpy.callCount).to.equal(4); }); }); describe("Finalize", () => { describe("_finalize", () => { const suite = SUITES_FIXTURE[1]; const syncStart = 8000; const syncEnd = 10000; const asyncStart = 12000; const asyncEnd = 13000; before(async () => { stub(runner, "_measuredValues").value({ tests: {}, }); stubPerformanceNowCalls(syncStart, syncEnd, asyncStart, asyncEnd); // instantiate recorded test results await runner._runTestAndRecordResults(suite, suite.tests[0]); await runner._finalize(); }); it("should calculate measured test values correctly", () => { const syncTime = syncEnd - syncStart; const asyncTime = asyncEnd - asyncStart; const total = syncTime + asyncTime; const mean = total / suite.tests.length; const geomean = Math.pow(total, 1 / suite.tests.length); const score = 1000 / geomean; const { total: measuredTotal, mean: measuredMean, geomean: measuredGeomean, score: measuredScore } = runner._measuredValues; expect(measuredTotal).to.equal(total); expect(measuredMean).to.equal(mean); expect(measuredGeomean).to.equal(geomean); expect(measuredScore).to.equal(score); assert.calledWith(runner._client.didRunSuites, runner._measuredValues); }); }); }); }); });