"use strict";
const {
createDoc,
expect,
createXmlTemplaterDocxNoRender,
browserMatches,
} = require("./utils");
const { times } = require("lodash");
const inspectModule = require("../inspect-module.js");
describe("Speed test", function () {
it("should be fast for simple tags", function () {
const content = "tag {age}";
const docs = [];
for (let i = 0; i < 100; i++) {
docs.push(createXmlTemplaterDocxNoRender(content, { tags: { age: 12 } }));
}
const time = new Date();
for (let i = 0; i < 100; i++) {
docs[i].render();
}
const duration = new Date() - time;
expect(duration).to.be.below(400);
});
it("should be fast for simple tags with huge content", function () {
let content = "tag {age}";
let i;
const result = [];
for (i = 1; i <= 10000; i++) {
result.push("bla");
}
const prepost = result.join("");
content = prepost + content + prepost;
const docs = [];
for (i = 0; i < 20; i++) {
docs.push(createXmlTemplaterDocxNoRender(content, { tags: { age: 12 } }));
}
const time = new Date();
for (i = 0; i < 20; i++) {
docs[i].render();
}
const duration = new Date() - time;
expect(duration).to.be.below(400);
});
it("should be fast for loop tags", function () {
const content = "{#users}{name}{/users}";
const users = [];
for (let i = 1; i <= 1000; i++) {
users.push({ name: "foo" });
}
const doc = createXmlTemplaterDocxNoRender(content, { tags: { users } });
const time = new Date();
doc.render();
const duration = new Date() - time;
let maxDuration = 100;
if (
browserMatches(/firefox (55|60|64|65)/) ||
browserMatches(/MicrosoftEdge (16)/)
) {
maxDuration = 150;
}
expect(duration).to.be.below(maxDuration);
});
it("should be fast for nested loop tags", function () {
const result = [];
for (let i = 1; i <= 300; i++) {
result.push(`
{#users} Names : {user}
{/}
`);
}
const prepost = result.join("");
const content = `{#foo}${prepost}{/}`;
const users = [{ name: "John" }, { name: "Mary" }];
const doc = createXmlTemplaterDocxNoRender(content, { tags: { users } });
const time = new Date();
doc.render();
const duration = new Date() - time;
let maxDuration = 300;
if (
browserMatches(/MicrosoftEdge (16|17|18)/) ||
browserMatches(/internet explorer (10|11)/) ||
browserMatches(/iphone 10.3/)
) {
maxDuration = 500;
}
expect(duration).to.be.below(maxDuration);
});
/* eslint-disable-next-line no-process-env */
if (!process.env.FAST) {
it("should not exceed call stack size for big document with a few rawxml tags", function () {
this.timeout(30000);
const result = [];
const normalContent = "foo";
const rawContent = "{@raw}";
for (let i = 1; i <= 30000; i++) {
if (i % 100 === 1) {
result.push(rawContent);
}
result.push(normalContent);
}
const content = result.join("");
const users = [];
const doc = createXmlTemplaterDocxNoRender(content, { tags: { users } });
let now = new Date();
doc.compile();
const compileDuration = new Date() - now;
if (typeof window === "undefined") {
// Skip this assertion in the browser
expect(compileDuration).to.be.below(3000);
}
now = new Date();
doc.render();
const renderDuration = new Date() - now;
expect(renderDuration).to.be.below(2000);
});
it("should not exceed call stack size for big document with many rawxml tags", function () {
this.timeout(30000);
const result = [];
const normalContent = "foo";
const rawContent = "{@raw}";
for (let i = 1; i <= 50000; i++) {
if (i % 2 === 1) {
result.push(rawContent);
}
result.push(normalContent);
}
const content = result.join("");
const users = [];
const doc = createXmlTemplaterDocxNoRender(content, { tags: { users } });
let now = new Date();
doc.compile();
const compileDuration = new Date() - now;
if (typeof window === "undefined") {
// Skip this assertion in the browser
expect(compileDuration).to.be.below(3000);
}
now = new Date();
doc.render();
const renderDuration = new Date() - now;
expect(renderDuration).to.be.below(2000);
});
describe("Inspect module", function () {
it("should not be slow after multiple generations", function () {
let duration = 0;
const iModule = inspectModule();
for (let i = 0; i < 10; i++) {
const doc = createDoc("tag-product-loop.docx");
const startTime = new Date();
doc.attachModule(iModule);
const data = {
nom: "Doe",
prenom: "John",
telephone: "0652455478",
description: "New Website",
offre: times(20000, (i) => {
return {
prix: 1000 + i,
nom: "Acme" + i,
};
}),
};
doc.setData(data);
doc.compile();
doc.render();
duration += new Date() - startTime;
}
expect(duration).to.be.below(750);
});
});
it("should not be slow when having many loops with resolveData", function () {
this.timeout(30000);
const OldPromise = global.Promise;
let resolveCount = 0;
let allCount = 0;
let parserCount = 0;
let parserGetCount = 0;
global.Promise = function (arg1, arg2) {
return new OldPromise(arg1, arg2);
};
global.Promise.resolve = function (arg1) {
resolveCount++;
return OldPromise.resolve(arg1);
};
global.Promise.all = function (arg1) {
allCount++;
return OldPromise.all(arg1);
};
const doc = createDoc("multi-level.docx");
doc.setOptions({
paragraphLoop: true,
parser: (tag) => {
parserCount++;
return {
get: (scope) => {
parserGetCount++;
return scope[tag];
},
};
},
});
let start = +new Date();
doc.compile();
const stepCompile = +new Date() - start;
start = +new Date();
const multiplier = 20;
const total = Math.pow(multiplier, 3);
const data = {
l1: times(multiplier),
l2: times(multiplier),
l3: times(multiplier, () => ({ content: "Hello" })),
};
return doc.resolveData(data).then(function () {
const stepResolve = +new Date() - start;
start = +new Date();
doc.render();
const stepRender = +new Date() - start;
expect(stepCompile).to.be.below(100);
let maxResolveTime = 2000;
if (browserMatches(/MicrosoftEdge (16|17|18)/)) {
maxResolveTime = 20000;
}
if (browserMatches(/firefox 55/)) {
maxResolveTime = 4000;
}
expect(stepResolve).to.be.below(maxResolveTime);
let maxRenderTime = 1000;
if (
browserMatches(/iphone 10.3/) ||
browserMatches(/MicrosoftEdge (16|17|18)/)
) {
maxRenderTime = 2000;
}
expect(stepRender).to.be.below(maxRenderTime);
expect(parserCount).to.be.equal(4);
// 20**3 + 20**2 *3 + 20 * 2 + 1 = 9241
expect(parserGetCount).to.be.equal(9241);
expect(resolveCount).to.be.within(total, total * 1.2);
expect(allCount).to.be.within(total, total * 1.2);
global.Promise = OldPromise;
});
});
}
});