094ff38da0
- since resetForm function reset a field value a calculateNow is consequently triggered. But the calculate callback can itself call resetForm, hence an infinite recursive loop. So basically, prevent calculeNow to be triggered by itself. - in Firefox, the letters entered in some fields were duplicated: "AaBb" instead of "AB". It was mainly because beforeInput was triggering a Keystroke which was itself triggering an input value update and then the input event was triggered. So in order to avoid that, beforeInput calls preventDefault and then it's up to the JS to handle the event. - fields have a property valueAsString which returns the value as a string. In the implementation it was wrongly used to store the formatted value of a field (2€ when the user entered 2). So this patch implements correctly valueAsString. - non-rendered fields can be updated in using JS but when they're, they must take some properties in the annotationStorage. It was implemented for field values, but it wasn't for display, colors, ... - it fixes #14862 and #14705.
1411 lines
40 KiB
JavaScript
1411 lines
40 KiB
JavaScript
/* Copyright 2020 Mozilla Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import { loadScript } from "../../src/display/display_utils.js";
|
|
|
|
const sandboxBundleSrc = "../../build/generic/build/pdf.sandbox.js";
|
|
|
|
describe("Scripting", function () {
|
|
let sandbox, send_queue, test_id, ref, windowAlert;
|
|
|
|
function getId() {
|
|
const id = `${ref++}R`;
|
|
return id;
|
|
}
|
|
|
|
function myeval(code) {
|
|
const key = (test_id++).toString();
|
|
return sandbox.eval(code, key).then(() => {
|
|
const result = send_queue.get(key).result;
|
|
send_queue.delete(key);
|
|
return result;
|
|
});
|
|
}
|
|
|
|
beforeAll(function () {
|
|
test_id = 0;
|
|
ref = 1;
|
|
send_queue = new Map();
|
|
window.dispatchEvent = event => {
|
|
if (event.detail.command) {
|
|
send_queue.set(event.detail.command, event.detail);
|
|
} else if (send_queue.has(event.detail.id)) {
|
|
const prev = send_queue.get(event.detail.id);
|
|
Object.assign(prev, event.detail);
|
|
} else {
|
|
send_queue.set(event.detail.id, event.detail);
|
|
}
|
|
};
|
|
windowAlert = window.alert;
|
|
window.alert = value => {
|
|
const command = "alert";
|
|
send_queue.set(command, { command, value });
|
|
};
|
|
const promise = loadScript(sandboxBundleSrc).then(() => {
|
|
return window.pdfjsSandbox.QuickJSSandbox();
|
|
});
|
|
sandbox = {
|
|
createSandbox(data) {
|
|
promise.then(sbx => sbx.create(data));
|
|
},
|
|
dispatchEventInSandbox(data) {
|
|
return promise.then(sbx => sbx.dispatchEvent(data));
|
|
},
|
|
nukeSandbox() {
|
|
promise.then(sbx => sbx.nukeSandbox());
|
|
},
|
|
eval(code, key) {
|
|
return promise.then(sbx => sbx.evalForTesting(code, key));
|
|
},
|
|
};
|
|
});
|
|
|
|
afterAll(function () {
|
|
sandbox.nukeSandbox();
|
|
sandbox = null;
|
|
send_queue = null;
|
|
window.alert = windowAlert;
|
|
});
|
|
|
|
describe("Sandbox", function () {
|
|
it("should send a value, execute an action and get back a new value", async () => {
|
|
function compute(n) {
|
|
let s = 0;
|
|
for (let i = 0; i < n; i++) {
|
|
s += i;
|
|
}
|
|
return s;
|
|
}
|
|
const number = 123;
|
|
const expected = ((number - 1) * number) / 2;
|
|
const refId = getId();
|
|
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
Keystroke: [
|
|
`${compute.toString()}event.value = compute(parseInt(event.value));`,
|
|
],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
calculationOrder: [],
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
};
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: `${number}`,
|
|
name: "Keystroke",
|
|
willCommit: true,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: expected,
|
|
formattedValue: null,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Doc", function () {
|
|
it("should treat globalThis as the doc", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
sandbox.createSandbox(data);
|
|
|
|
await myeval(`(this.foobar = 123456, 0)`);
|
|
const value = await myeval(`this.getField("field").doc.foobar`);
|
|
expect(value).toEqual(123456);
|
|
});
|
|
|
|
it("should get field using a path", async () => {
|
|
const base = value => {
|
|
return {
|
|
id: getId(),
|
|
value,
|
|
actions: {},
|
|
type: "text",
|
|
};
|
|
};
|
|
const data = {
|
|
objects: {
|
|
A: [base(1)],
|
|
"A.B": [base(2)],
|
|
"A.B.C": [base(3)],
|
|
"A.B.C.D": [base(4)],
|
|
"A.B.C.D.E": [base(5)],
|
|
"A.B.C.D.E.F": [base(6)],
|
|
"A.B.C.D.G": [base(7)],
|
|
C: [base(8)],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
sandbox.createSandbox(data);
|
|
|
|
let value = await myeval(`this.getField("A").value`);
|
|
expect(value).toEqual(1);
|
|
|
|
value = await myeval(`this.getField("B.C").value`);
|
|
expect(value).toEqual(3);
|
|
|
|
// path has been cached so try again
|
|
value = await myeval(`this.getField("B.C").value`);
|
|
expect(value).toEqual(3);
|
|
|
|
value = await myeval(`this.getField("B.C.D#0").value`);
|
|
expect(value).toEqual(5);
|
|
|
|
value = await myeval(`this.getField("B.C.D#1").value`);
|
|
expect(value).toEqual(7);
|
|
|
|
value = await myeval(`this.getField("C").value`);
|
|
expect(value).toEqual(8);
|
|
|
|
value = await myeval(
|
|
`this.getField("A.B.C.D").getArray().map((x) => x.value)`
|
|
);
|
|
expect(value).toEqual([5, 7]);
|
|
});
|
|
});
|
|
|
|
describe("Util", function () {
|
|
beforeAll(function () {
|
|
sandbox.createSandbox({
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
objects: {},
|
|
calculationOrder: [],
|
|
});
|
|
});
|
|
|
|
describe("printd", function () {
|
|
it("should print a date according to a format", async () => {
|
|
const date = `new Date("Sun Apr 15 2007 03:14:15")`;
|
|
let value = await myeval(`util.printd(0, ${date})`);
|
|
expect(value).toEqual("D:20070415031415");
|
|
|
|
value = await myeval(`util.printd(1, ${date})`);
|
|
expect(value).toEqual("2007.04.15 03:14:15");
|
|
|
|
value = await myeval(`util.printd(2, ${date})`);
|
|
expect(value).toEqual("4/15/07 3:14:15 am");
|
|
|
|
value = await myeval(`util.printd("mmmm mmm mm m", ${date})`);
|
|
expect(value).toEqual("April Apr 04 4");
|
|
|
|
value = await myeval(`util.printd("dddd ddd dd d", ${date})`);
|
|
expect(value).toEqual("Sunday Sun 15 15");
|
|
});
|
|
});
|
|
|
|
describe("scand", function () {
|
|
it("should parse a date according to a format", async () => {
|
|
const date = new Date("Sun Apr 15 2007 03:14:15");
|
|
let value = await myeval(
|
|
`util.scand(0, "D:20070415031415").toString()`
|
|
);
|
|
expect(new Date(value)).toEqual(date);
|
|
|
|
value = await myeval(`util.scand(1, "2007.04.15 03:14:15").toString()`);
|
|
expect(new Date(value)).toEqual(date);
|
|
|
|
value = await myeval(`util.scand(2, "4/15/07 3:14:15 am").toString()`);
|
|
expect(new Date(value)).toEqual(date);
|
|
});
|
|
});
|
|
|
|
describe("printf", function () {
|
|
it("should print some data according to a format", async () => {
|
|
let value = await myeval(
|
|
`util.printf("Integer numbers: %d, %d,...", 1.234, 56.789)`
|
|
);
|
|
expect(value).toEqual("Integer numbers: 1, 56,...");
|
|
|
|
value = await myeval(
|
|
`util.printf("Hex numbers: %x, %x,...", 1234, 56789)`
|
|
);
|
|
expect(value).toEqual("Hex numbers: 4D2, DDD5,...");
|
|
|
|
value = await myeval(
|
|
`util.printf("Hex numbers with 0x: %#x, %#x,...", 1234, 56789)`
|
|
);
|
|
expect(value).toEqual("Hex numbers with 0x: 0x4D2, 0xDDD5,...");
|
|
|
|
value = await myeval(
|
|
`util.printf("Decimal number: %,0+.3f", 1234567.89123)`
|
|
);
|
|
expect(value).toEqual("Decimal number: +1,234,567.891");
|
|
|
|
value = await myeval(
|
|
`util.printf("Decimal number: %,0+8.3f", 1.234567)`
|
|
);
|
|
expect(value).toEqual("Decimal number: + 1.235");
|
|
|
|
value = await myeval(
|
|
`util.printf("Decimal number: %,0.2f", -12.34567)`
|
|
);
|
|
expect(value).toEqual("Decimal number: -12.35");
|
|
});
|
|
|
|
it("should print a string with no argument", async () => {
|
|
const value = await myeval(`util.printf("hello world")`);
|
|
expect(value).toEqual("hello world");
|
|
});
|
|
|
|
it("print a string with a percent", async () => {
|
|
const value = await myeval(`util.printf("%%s")`);
|
|
expect(value).toEqual("%%s");
|
|
});
|
|
});
|
|
|
|
describe("printx", function () {
|
|
it("should print some data according to a format", async () => {
|
|
const value = await myeval(
|
|
`util.printx("9 (999) 999-9999", "aaa14159697489zzz")`
|
|
);
|
|
expect(value).toEqual("1 (415) 969-7489");
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Events", function () {
|
|
it("should trigger an event and modify the source", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
test: [`event.source.value = "123";`],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
};
|
|
sandbox.createSandbox(data);
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "",
|
|
name: "test",
|
|
willCommit: true,
|
|
});
|
|
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "123",
|
|
});
|
|
});
|
|
|
|
it("should trigger a Keystroke event and invalidate it", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
Keystroke: [`event.rc = false;`],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
};
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "hell",
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
change: "o",
|
|
selStart: 4,
|
|
selEnd: 4,
|
|
});
|
|
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "hell",
|
|
selRange: [4, 4],
|
|
});
|
|
});
|
|
|
|
it("should trigger a Keystroke event and change it", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
Keystroke: [`event.change = "a";`],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
};
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "hell",
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
change: "o",
|
|
selStart: 4,
|
|
selEnd: 4,
|
|
});
|
|
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "hella",
|
|
selRange: [5, 5],
|
|
});
|
|
});
|
|
|
|
it("should trigger an invalid commit Keystroke event", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
test: [`event.rc = false;`],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
};
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "",
|
|
name: "test",
|
|
willCommit: true,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(false);
|
|
});
|
|
|
|
it("should trigger a valid commit Keystroke event", async () => {
|
|
const refId1 = getId();
|
|
const refId2 = getId();
|
|
const data = {
|
|
objects: {
|
|
field1: [
|
|
{
|
|
id: refId1,
|
|
value: "",
|
|
actions: {
|
|
Validate: [`event.value = "world";`],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
field2: [
|
|
{
|
|
id: refId2,
|
|
value: "",
|
|
actions: {
|
|
Calculate: [`event.value = "hello";`],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [refId2],
|
|
};
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId1,
|
|
value: "hello",
|
|
name: "Keystroke",
|
|
willCommit: true,
|
|
});
|
|
|
|
expect(send_queue.has(refId1)).toEqual(true);
|
|
expect(send_queue.get(refId1)).toEqual({
|
|
id: refId1,
|
|
value: "world",
|
|
formattedValue: null,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Color", function () {
|
|
beforeAll(function () {
|
|
sandbox.createSandbox({
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
objects: {},
|
|
calculationOrder: [],
|
|
});
|
|
});
|
|
|
|
function round(color) {
|
|
return [
|
|
color[0],
|
|
...color.slice(1).map(x => Math.round(x * 1000) / 1000),
|
|
];
|
|
}
|
|
|
|
it("should convert RGB color for different color spaces", async () => {
|
|
let value = await myeval(`color.convert(["RGB", 0.1, 0.2, 0.3], "T")`);
|
|
expect(round(value)).toEqual(["T"]);
|
|
|
|
value = await myeval(`color.convert(["RGB", 0.1, 0.2, 0.3], "G")`);
|
|
expect(round(value)).toEqual(["G", 0.181]);
|
|
|
|
value = await myeval(`color.convert(["RGB", 0.1, 0.2, 0.3], "RGB")`);
|
|
expect(round(value)).toEqual(["RGB", 0.1, 0.2, 0.3]);
|
|
|
|
value = await myeval(`color.convert(["RGB", 0.1, 0.2, 0.3], "CMYK")`);
|
|
expect(round(value)).toEqual(["CMYK", 0.9, 0.8, 0.7, 0.7]);
|
|
});
|
|
|
|
it("should convert CMYK color for different color spaces", async () => {
|
|
let value = await myeval(
|
|
`color.convert(["CMYK", 0.1, 0.2, 0.3, 0.4], "T")`
|
|
);
|
|
expect(round(value)).toEqual(["T"]);
|
|
|
|
value = await myeval(`color.convert(["CMYK", 0.1, 0.2, 0.3, 0.4], "G")`);
|
|
expect(round(value)).toEqual(["G", 0.371]);
|
|
|
|
value = await myeval(
|
|
`color.convert(["CMYK", 0.1, 0.2, 0.3, 0.4], "RGB")`
|
|
);
|
|
expect(round(value)).toEqual(["RGB", 0.5, 0.3, 0.4]);
|
|
|
|
value = await myeval(
|
|
`color.convert(["CMYK", 0.1, 0.2, 0.3, 0.4], "CMYK")`
|
|
);
|
|
expect(round(value)).toEqual(["CMYK", 0.1, 0.2, 0.3, 0.4]);
|
|
});
|
|
|
|
it("should convert Gray color for different color spaces", async () => {
|
|
let value = await myeval(`color.convert(["G", 0.1], "T")`);
|
|
expect(round(value)).toEqual(["T"]);
|
|
|
|
value = await myeval(`color.convert(["G", 0.1], "G")`);
|
|
expect(round(value)).toEqual(["G", 0.1]);
|
|
|
|
value = await myeval(`color.convert(["G", 0.1], "RGB")`);
|
|
expect(round(value)).toEqual(["RGB", 0.1, 0.1, 0.1]);
|
|
|
|
value = await myeval(`color.convert(["G", 0.1], "CMYK")`);
|
|
expect(round(value)).toEqual(["CMYK", 0, 0, 0, 0.9]);
|
|
});
|
|
|
|
it("should convert Transparent color for different color spaces", async () => {
|
|
let value = await myeval(`color.convert(["T"], "T")`);
|
|
expect(round(value)).toEqual(["T"]);
|
|
|
|
value = await myeval(`color.convert(["T"], "G")`);
|
|
expect(round(value)).toEqual(["G", 0]);
|
|
|
|
value = await myeval(`color.convert(["T"], "RGB")`);
|
|
expect(round(value)).toEqual(["RGB", 0, 0, 0]);
|
|
|
|
value = await myeval(`color.convert(["T"], "CMYK")`);
|
|
expect(round(value)).toEqual(["CMYK", 0, 0, 0, 1]);
|
|
});
|
|
});
|
|
|
|
describe("App", function () {
|
|
beforeAll(function () {
|
|
sandbox.createSandbox({
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
objects: {},
|
|
calculationOrder: [],
|
|
});
|
|
});
|
|
|
|
it("should test language", async () => {
|
|
let value = await myeval(`app.language`);
|
|
expect(value).toEqual("ENU");
|
|
|
|
value = await myeval(`app.language = "hello"`);
|
|
expect(value).toEqual("app.language is read-only");
|
|
});
|
|
|
|
it("should test platform", async () => {
|
|
let value = await myeval(`app.platform`);
|
|
expect(value).toEqual("UNIX");
|
|
|
|
value = await myeval(`app.platform = "hello"`);
|
|
expect(value).toEqual("app.platform is read-only");
|
|
});
|
|
});
|
|
|
|
describe("AForm", function () {
|
|
beforeAll(function () {
|
|
sandbox.createSandbox({
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
objects: {},
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
});
|
|
});
|
|
|
|
describe("AFParseDateEx", function () {
|
|
it("should parse a date with a format", async () => {
|
|
const check = async (date, format, expected) => {
|
|
const value = await myeval(
|
|
`AFParseDateEx("${date}", "${format}").toISOString()`
|
|
);
|
|
expect(value).toEqual(new Date(expected).toISOString());
|
|
};
|
|
|
|
await check("05", "dd", "2000/01/05");
|
|
await check("12", "mm", "2000/12/01");
|
|
await check("2022", "yyyy", "2022/01/01");
|
|
});
|
|
});
|
|
|
|
describe("AFExtractNums", function () {
|
|
it("should extract numbers", async () => {
|
|
let value = await myeval(`AFExtractNums("123 456 789")`);
|
|
expect(value).toEqual(["123", "456", "789"]);
|
|
|
|
value = await myeval(`AFExtractNums("123.456")`);
|
|
expect(value).toEqual(["123", "456"]);
|
|
|
|
value = await myeval(`AFExtractNums("123")`);
|
|
expect(value).toEqual(["123"]);
|
|
|
|
value = await myeval(`AFExtractNums(".123")`);
|
|
expect(value).toEqual(["0", "123"]);
|
|
|
|
value = await myeval(`AFExtractNums(",123")`);
|
|
expect(value).toEqual(["0", "123"]);
|
|
});
|
|
});
|
|
|
|
describe("AFMakeNumber", function () {
|
|
it("should convert string to number", async () => {
|
|
let value = await myeval(`AFMakeNumber("123.456")`);
|
|
expect(value).toEqual(123.456);
|
|
|
|
value = await myeval(`AFMakeNumber(123.456)`);
|
|
expect(value).toEqual(123.456);
|
|
|
|
value = await myeval(`AFMakeNumber("-123.456")`);
|
|
expect(value).toEqual(-123.456);
|
|
|
|
value = await myeval(`AFMakeNumber("-123,456")`);
|
|
expect(value).toEqual(-123.456);
|
|
|
|
value = await myeval(`AFMakeNumber("not a number")`);
|
|
expect(value).toEqual(null);
|
|
});
|
|
});
|
|
|
|
describe("AFMakeArrayFromList", function () {
|
|
it("should split a string into an array of strings", async () => {
|
|
const value = await myeval(
|
|
`AFMakeArrayFromList("aaaa, bbbbbbb,cc,ddd, e")`
|
|
);
|
|
expect(value).toEqual(["aaaa", " bbbbbbb", "cc", "ddd", "e"]);
|
|
});
|
|
});
|
|
|
|
describe("AFNumber_format", function () {
|
|
it("should format a number", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
test1: [
|
|
`AFNumber_Format(2, 0, 0, 0, "€", false);` +
|
|
`event.source.value = event.value;`,
|
|
],
|
|
test2: [
|
|
`AFNumber_Format(1, 3, 0, 0, "$", true);` +
|
|
`event.source.value = event.value;`,
|
|
],
|
|
test3: [
|
|
`AFNumber_Format(2, 0, 1, 0, "€", false);` +
|
|
`event.source.value = event.value;`,
|
|
],
|
|
test4: [
|
|
`AFNumber_Format(2, 0, 2, 0, "€", false);` +
|
|
`event.source.value = event.value;`,
|
|
],
|
|
test5: [
|
|
`AFNumber_Format(2, 0, 3, 0, "€", false);` +
|
|
`event.source.value = event.value;`,
|
|
],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "123456.789",
|
|
name: "test1",
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "123,456.79€",
|
|
});
|
|
send_queue.delete(refId);
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "223456.789",
|
|
name: "test2",
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "$223456,8",
|
|
});
|
|
send_queue.delete(refId);
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "-323456.789",
|
|
name: "test3",
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "323,456.79€",
|
|
textColor: ["RGB", 1, 0, 0],
|
|
});
|
|
send_queue.delete(refId);
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "-423456.789",
|
|
name: "test4",
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "(423,456.79€)",
|
|
});
|
|
send_queue.delete(refId);
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "-52345.678",
|
|
name: "test5",
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "(52,345.68€)",
|
|
textColor: ["RGB", 1, 0, 0],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("AFNumber_Keystroke", function () {
|
|
it("should validate a number on a keystroke event", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
Validate: [
|
|
`AFNumber_Keystroke(null, 0, null, null, null, null);`,
|
|
],
|
|
},
|
|
type: "text",
|
|
name: "MyField",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "123456.789",
|
|
name: "Keystroke",
|
|
willCommit: true,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "123456.789",
|
|
formattedValue: null,
|
|
});
|
|
});
|
|
|
|
it("should not validate a number on a keystroke event", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
Validate: [
|
|
`AFNumber_Keystroke(null, 0, null, null, null, null);`,
|
|
],
|
|
},
|
|
type: "text",
|
|
name: "MyField",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "123s456.789",
|
|
name: "Keystroke",
|
|
willCommit: true,
|
|
});
|
|
expect(send_queue.has("alert")).toEqual(true);
|
|
expect(send_queue.get("alert")).toEqual({
|
|
command: "alert",
|
|
value:
|
|
"The value entered does not match the format of the field [ MyField ]",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("AFPercent_Format", function () {
|
|
it("should format a percentage", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
test1: [
|
|
`AFPercent_Format(2, 1, false);` +
|
|
`event.source.value = event.value;`,
|
|
],
|
|
test2: [
|
|
`AFPercent_Format(2, 1, true);` +
|
|
`event.source.value = event.value;`,
|
|
],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "0.456789",
|
|
name: "test1",
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "45.68%",
|
|
});
|
|
send_queue.delete(refId);
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "0.456789",
|
|
name: "test2",
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "%45.68",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("AFDate_Format", function () {
|
|
it("should format a date", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
test1: [`AFDate_Format(0);event.source.value = event.value;`],
|
|
test2: [
|
|
`AFDate_Format(12);event.source.value = event.value;`,
|
|
],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "Sun Apr 15 2007 03:14:15",
|
|
name: "test1",
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "4/15",
|
|
});
|
|
send_queue.delete(refId);
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "Sun Apr 15 2007 03:14:15",
|
|
name: "test2",
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "4/15/07 3:14 am",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("AFRange_Validate", function () {
|
|
it("should validate a number in range [a, b]", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
Validate: [`AFRange_Validate(true, 123, true, 456);`],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "321",
|
|
name: "Keystroke",
|
|
willCommit: true,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "321",
|
|
formattedValue: null,
|
|
});
|
|
});
|
|
|
|
it("should invalidate a number out of range [a, b]", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
Validate: [`AFRange_Validate(true, 123, true, 456);`],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "12",
|
|
name: "Keystroke",
|
|
willCommit: true,
|
|
});
|
|
expect(send_queue.has("alert")).toEqual(true);
|
|
expect(send_queue.get("alert")).toEqual({
|
|
command: "alert",
|
|
value:
|
|
"Invalid value: must be greater than or equal to 123 and less than or equal to 456.",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("ASSimple_Calculate", function () {
|
|
it("should compute the sum of several fields", async () => {
|
|
const refIds = [0, 1, 2, 3].map(_ => getId());
|
|
const data = {
|
|
objects: {
|
|
field1: [
|
|
{
|
|
id: refIds[0],
|
|
value: "",
|
|
actions: {},
|
|
type: "text",
|
|
},
|
|
],
|
|
field2: [
|
|
{
|
|
id: refIds[1],
|
|
value: "",
|
|
actions: {},
|
|
type: "text",
|
|
},
|
|
],
|
|
field3: [
|
|
{
|
|
id: refIds[2],
|
|
value: "",
|
|
actions: {},
|
|
type: "text",
|
|
},
|
|
],
|
|
field4: [
|
|
{
|
|
id: refIds[3],
|
|
value: "",
|
|
actions: {
|
|
Calculate: [
|
|
`AFSimple_Calculate("SUM", ["field1", "field2", "field3"]);`,
|
|
],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [refIds[3]],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refIds[0],
|
|
value: "1",
|
|
name: "Keystroke",
|
|
willCommit: true,
|
|
});
|
|
expect(send_queue.has(refIds[3])).toEqual(true);
|
|
expect(send_queue.get(refIds[3])).toEqual({
|
|
id: refIds[3],
|
|
value: 1,
|
|
formattedValue: null,
|
|
});
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refIds[1],
|
|
value: "2",
|
|
name: "Keystroke",
|
|
willCommit: true,
|
|
});
|
|
expect(send_queue.has(refIds[3])).toEqual(true);
|
|
expect(send_queue.get(refIds[3])).toEqual({
|
|
id: refIds[3],
|
|
value: 3,
|
|
formattedValue: null,
|
|
});
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refIds[2],
|
|
value: "3",
|
|
name: "Keystroke",
|
|
willCommit: true,
|
|
});
|
|
expect(send_queue.has(refIds[3])).toEqual(true);
|
|
expect(send_queue.get(refIds[3])).toEqual({
|
|
id: refIds[3],
|
|
value: 6,
|
|
formattedValue: null,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("AFSpecial_KeystrokeEx", function () {
|
|
it("should validate a phone number on a keystroke event", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
Keystroke: [`AFSpecial_KeystrokeEx("9AXO");`],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
sandbox.createSandbox(data);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "",
|
|
change: "3",
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
selStart: 0,
|
|
selEnd: 0,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
send_queue.delete(refId);
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "3",
|
|
change: "F",
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
selStart: 1,
|
|
selEnd: 1,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
send_queue.delete(refId);
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "3F",
|
|
change: "?",
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
selStart: 2,
|
|
selEnd: 2,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
send_queue.delete(refId);
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "3F?",
|
|
change: "@",
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
selStart: 3,
|
|
selEnd: 3,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "3F?",
|
|
selRange: [3, 3],
|
|
});
|
|
|
|
send_queue.delete(refId);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "3F?",
|
|
change: "0",
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
selStart: 3,
|
|
selEnd: 3,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
send_queue.delete(refId);
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value: "3F?0",
|
|
name: "Keystroke",
|
|
willCommit: true,
|
|
selStart: 4,
|
|
selEnd: 4,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value: "3F?0",
|
|
formattedValue: null,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("AFSpecial_Keystroke", function () {
|
|
it("should validate a zip code on a keystroke event", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
Keystroke: [`AFSpecial_Keystroke(0);`],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
sandbox.createSandbox(data);
|
|
|
|
let value = "";
|
|
const changes = "12345";
|
|
let i = 0;
|
|
|
|
for (; i < changes.length; i++) {
|
|
const change = changes.charAt(i);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value,
|
|
change,
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
selStart: i,
|
|
selEnd: i,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
send_queue.delete(refId);
|
|
value += change;
|
|
}
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value,
|
|
change: "A",
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
selStart: i,
|
|
selEnd: i,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value,
|
|
selRange: [i, i],
|
|
});
|
|
|
|
send_queue.delete(refId);
|
|
});
|
|
|
|
it("should validate a US phone number (long) on a keystroke event", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
Keystroke: [`AFSpecial_Keystroke(2);`],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
sandbox.createSandbox(data);
|
|
|
|
let value = "";
|
|
const changes = "(123) 456-7890";
|
|
let i = 0;
|
|
|
|
for (; i < changes.length; i++) {
|
|
const change = changes.charAt(i);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value,
|
|
change,
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
selStart: i,
|
|
selEnd: i,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
send_queue.delete(refId);
|
|
value += change;
|
|
}
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value,
|
|
change: "A",
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
selStart: i,
|
|
selEnd: i,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value,
|
|
selRange: [i, i],
|
|
});
|
|
|
|
send_queue.delete(refId);
|
|
});
|
|
|
|
it("should validate a US phone number (short) on a keystroke event", async () => {
|
|
const refId = getId();
|
|
const data = {
|
|
objects: {
|
|
field: [
|
|
{
|
|
id: refId,
|
|
value: "",
|
|
actions: {
|
|
Keystroke: [`AFSpecial_Keystroke(2);`],
|
|
},
|
|
type: "text",
|
|
},
|
|
],
|
|
},
|
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
|
calculationOrder: [],
|
|
dispatchEventName: "_dispatchMe",
|
|
};
|
|
sandbox.createSandbox(data);
|
|
|
|
let value = "";
|
|
const changes = "123-4567";
|
|
let i = 0;
|
|
|
|
for (; i < changes.length; i++) {
|
|
const change = changes.charAt(i);
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value,
|
|
change,
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
selStart: i,
|
|
selEnd: i,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
send_queue.delete(refId);
|
|
value += change;
|
|
}
|
|
|
|
await sandbox.dispatchEventInSandbox({
|
|
id: refId,
|
|
value,
|
|
change: "A",
|
|
name: "Keystroke",
|
|
willCommit: false,
|
|
selStart: i,
|
|
selEnd: i,
|
|
});
|
|
expect(send_queue.has(refId)).toEqual(true);
|
|
expect(send_queue.get(refId)).toEqual({
|
|
id: refId,
|
|
value,
|
|
selRange: [i, i],
|
|
});
|
|
|
|
send_queue.delete(refId);
|
|
});
|
|
});
|
|
|
|
describe("eMailValidate", function () {
|
|
it("should validate an e-mail address", async () => {
|
|
let value = await myeval(`eMailValidate(123)`);
|
|
expect(value).toEqual(false);
|
|
|
|
value = await myeval(`eMailValidate("foo@bar.com")`);
|
|
expect(value).toEqual(true);
|
|
|
|
value = await myeval(`eMailValidate("foo bar")`);
|
|
expect(value).toEqual(false);
|
|
});
|
|
});
|
|
});
|
|
});
|