2
0

scripting_spec.js 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * JavaScript code in this page
  4. *
  5. * Copyright 2022 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * JavaScript code in this page
  21. */
  22. "use strict";
  23. var _display_utils = require("../../display/display_utils.js");
  24. const sandboxBundleSrc = "../../build/generic/build/pdf.sandbox.js";
  25. describe("Scripting", function () {
  26. let sandbox, send_queue, test_id, ref, windowAlert;
  27. function getId() {
  28. const id = `${ref++}R`;
  29. return id;
  30. }
  31. function myeval(code) {
  32. const key = (test_id++).toString();
  33. return sandbox.eval(code, key).then(() => {
  34. const result = send_queue.get(key).result;
  35. send_queue.delete(key);
  36. return result;
  37. });
  38. }
  39. beforeAll(function () {
  40. test_id = 0;
  41. ref = 1;
  42. send_queue = new Map();
  43. window.dispatchEvent = event => {
  44. if (event.detail.command) {
  45. send_queue.set(event.detail.command, event.detail);
  46. } else if (send_queue.has(event.detail.id)) {
  47. const prev = send_queue.get(event.detail.id);
  48. Object.assign(prev, event.detail);
  49. } else {
  50. send_queue.set(event.detail.id, event.detail);
  51. }
  52. };
  53. windowAlert = window.alert;
  54. window.alert = value => {
  55. const command = "alert";
  56. send_queue.set(command, {
  57. command,
  58. value
  59. });
  60. };
  61. const promise = (0, _display_utils.loadScript)(sandboxBundleSrc).then(() => {
  62. return window.pdfjsSandbox.QuickJSSandbox();
  63. });
  64. sandbox = {
  65. createSandbox(data) {
  66. promise.then(sbx => sbx.create(data));
  67. },
  68. dispatchEventInSandbox(data) {
  69. return promise.then(sbx => sbx.dispatchEvent(data));
  70. },
  71. nukeSandbox() {
  72. promise.then(sbx => sbx.nukeSandbox());
  73. },
  74. eval(code, key) {
  75. return promise.then(sbx => sbx.evalForTesting(code, key));
  76. }
  77. };
  78. });
  79. afterAll(function () {
  80. sandbox.nukeSandbox();
  81. sandbox = null;
  82. send_queue = null;
  83. window.alert = windowAlert;
  84. });
  85. describe("Sandbox", function () {
  86. it("should send a value, execute an action and get back a new value", async () => {
  87. function compute(n) {
  88. let s = 0;
  89. for (let i = 0; i < n; i++) {
  90. s += i;
  91. }
  92. return s;
  93. }
  94. const number = 123;
  95. const expected = (number - 1) * number / 2;
  96. const refId = getId();
  97. const data = {
  98. objects: {
  99. field: [{
  100. id: refId,
  101. value: "",
  102. actions: {
  103. Keystroke: [`${compute.toString()}event.value = compute(parseInt(event.value));`]
  104. },
  105. type: "text"
  106. }]
  107. },
  108. calculationOrder: [],
  109. appInfo: {
  110. language: "en-US",
  111. platform: "Linux x86_64"
  112. }
  113. };
  114. sandbox.createSandbox(data);
  115. await sandbox.dispatchEventInSandbox({
  116. id: refId,
  117. value: `${number}`,
  118. name: "Keystroke",
  119. willCommit: true
  120. });
  121. expect(send_queue.has(refId)).toEqual(true);
  122. expect(send_queue.get(refId)).toEqual({
  123. id: refId,
  124. value: expected,
  125. formattedValue: null
  126. });
  127. });
  128. });
  129. describe("Doc", function () {
  130. it("should treat globalThis as the doc", async () => {
  131. const refId = getId();
  132. const data = {
  133. objects: {
  134. field: [{
  135. id: refId,
  136. value: "",
  137. actions: {},
  138. type: "text"
  139. }]
  140. },
  141. appInfo: {
  142. language: "en-US",
  143. platform: "Linux x86_64"
  144. },
  145. calculationOrder: [],
  146. dispatchEventName: "_dispatchMe"
  147. };
  148. sandbox.createSandbox(data);
  149. await myeval(`(this.foobar = 123456, 0)`);
  150. const value = await myeval(`this.getField("field").doc.foobar`);
  151. expect(value).toEqual(123456);
  152. });
  153. it("should get field using a path", async () => {
  154. const base = value => {
  155. return {
  156. id: getId(),
  157. value,
  158. actions: {},
  159. type: "text"
  160. };
  161. };
  162. const data = {
  163. objects: {
  164. A: [base(1)],
  165. "A.B": [base(2)],
  166. "A.B.C": [base(3)],
  167. "A.B.C.D": [base(4)],
  168. "A.B.C.D.E": [base(5)],
  169. "A.B.C.D.E.F": [base(6)],
  170. "A.B.C.D.G": [base(7)],
  171. C: [base(8)]
  172. },
  173. appInfo: {
  174. language: "en-US",
  175. platform: "Linux x86_64"
  176. },
  177. calculationOrder: [],
  178. dispatchEventName: "_dispatchMe"
  179. };
  180. sandbox.createSandbox(data);
  181. let value = await myeval(`this.getField("A").value`);
  182. expect(value).toEqual(1);
  183. value = await myeval(`this.getField("B.C").value`);
  184. expect(value).toEqual(3);
  185. value = await myeval(`this.getField("B.C").value`);
  186. expect(value).toEqual(3);
  187. value = await myeval(`this.getField("B.C.D#0").value`);
  188. expect(value).toEqual(5);
  189. value = await myeval(`this.getField("B.C.D#1").value`);
  190. expect(value).toEqual(7);
  191. value = await myeval(`this.getField("C").value`);
  192. expect(value).toEqual(8);
  193. value = await myeval(`this.getField("A.B.C.D").getArray().map((x) => x.value)`);
  194. expect(value).toEqual([5, 7]);
  195. });
  196. });
  197. describe("Util", function () {
  198. beforeAll(function () {
  199. sandbox.createSandbox({
  200. appInfo: {
  201. language: "en-US",
  202. platform: "Linux x86_64"
  203. },
  204. objects: {},
  205. calculationOrder: []
  206. });
  207. });
  208. describe("printd", function () {
  209. it("should print a date according to a format", async () => {
  210. const date = `new Date("Sun Apr 15 2007 03:14:15")`;
  211. let value = await myeval(`util.printd(0, ${date})`);
  212. expect(value).toEqual("D:20070415031415");
  213. value = await myeval(`util.printd(1, ${date})`);
  214. expect(value).toEqual("2007.04.15 03:14:15");
  215. value = await myeval(`util.printd(2, ${date})`);
  216. expect(value).toEqual("4/15/07 3:14:15 am");
  217. value = await myeval(`util.printd("mmmm mmm mm m", ${date})`);
  218. expect(value).toEqual("April Apr 04 4");
  219. value = await myeval(`util.printd("dddd ddd dd d", ${date})`);
  220. expect(value).toEqual("Sunday Sun 15 15");
  221. });
  222. });
  223. describe("scand", function () {
  224. it("should parse a date according to a format", async () => {
  225. const date = new Date("Sun Apr 15 2007 03:14:15");
  226. let value = await myeval(`util.scand(0, "D:20070415031415").toString()`);
  227. expect(new Date(value)).toEqual(date);
  228. value = await myeval(`util.scand(1, "2007.04.15 03:14:15").toString()`);
  229. expect(new Date(value)).toEqual(date);
  230. value = await myeval(`util.scand(2, "4/15/07 3:14:15 am").toString()`);
  231. expect(new Date(value)).toEqual(date);
  232. });
  233. });
  234. describe("printf", function () {
  235. it("should print some data according to a format", async () => {
  236. let value = await myeval(`util.printf("Integer numbers: %d, %d,...", 1.234, 56.789)`);
  237. expect(value).toEqual("Integer numbers: 1, 56,...");
  238. value = await myeval(`util.printf("Hex numbers: %x, %x,...", 1234, 56789)`);
  239. expect(value).toEqual("Hex numbers: 4D2, DDD5,...");
  240. value = await myeval(`util.printf("Hex numbers with 0x: %#x, %#x,...", 1234, 56789)`);
  241. expect(value).toEqual("Hex numbers with 0x: 0x4D2, 0xDDD5,...");
  242. value = await myeval(`util.printf("Decimal number: %,0+.3f", 1234567.89123)`);
  243. expect(value).toEqual("Decimal number: +1,234,567.891");
  244. value = await myeval(`util.printf("Decimal number: %,0+8.3f", 1.234567)`);
  245. expect(value).toEqual("Decimal number: + 1.235");
  246. value = await myeval(`util.printf("Decimal number: %,0.2f", -12.34567)`);
  247. expect(value).toEqual("Decimal number: -12.35");
  248. });
  249. it("should print a string with no argument", async () => {
  250. const value = await myeval(`util.printf("hello world")`);
  251. expect(value).toEqual("hello world");
  252. });
  253. it("print a string with a percent", async () => {
  254. const value = await myeval(`util.printf("%%s")`);
  255. expect(value).toEqual("%%s");
  256. });
  257. });
  258. describe("printx", function () {
  259. it("should print some data according to a format", async () => {
  260. const value = await myeval(`util.printx("9 (999) 999-9999", "aaa14159697489zzz")`);
  261. expect(value).toEqual("1 (415) 969-7489");
  262. });
  263. });
  264. });
  265. describe("Events", function () {
  266. it("should trigger an event and modify the source", async () => {
  267. const refId = getId();
  268. const data = {
  269. objects: {
  270. field: [{
  271. id: refId,
  272. value: "",
  273. actions: {
  274. test: [`event.source.value = "123";`]
  275. },
  276. type: "text"
  277. }]
  278. },
  279. appInfo: {
  280. language: "en-US",
  281. platform: "Linux x86_64"
  282. },
  283. calculationOrder: []
  284. };
  285. sandbox.createSandbox(data);
  286. await sandbox.dispatchEventInSandbox({
  287. id: refId,
  288. value: "",
  289. name: "test",
  290. willCommit: true
  291. });
  292. expect(send_queue.has(refId)).toEqual(true);
  293. expect(send_queue.get(refId)).toEqual({
  294. id: refId,
  295. value: "123"
  296. });
  297. });
  298. it("should trigger a Keystroke event and invalidate it", async () => {
  299. const refId = getId();
  300. const data = {
  301. objects: {
  302. field: [{
  303. id: refId,
  304. value: "",
  305. actions: {
  306. Keystroke: [`event.rc = false;`]
  307. },
  308. type: "text"
  309. }]
  310. },
  311. appInfo: {
  312. language: "en-US",
  313. platform: "Linux x86_64"
  314. },
  315. calculationOrder: []
  316. };
  317. sandbox.createSandbox(data);
  318. await sandbox.dispatchEventInSandbox({
  319. id: refId,
  320. value: "hell",
  321. name: "Keystroke",
  322. willCommit: false,
  323. change: "o",
  324. selStart: 4,
  325. selEnd: 4
  326. });
  327. expect(send_queue.has(refId)).toEqual(true);
  328. expect(send_queue.get(refId)).toEqual({
  329. id: refId,
  330. value: "hell",
  331. selRange: [4, 4]
  332. });
  333. });
  334. it("should trigger a Keystroke event and change it", async () => {
  335. const refId = getId();
  336. const data = {
  337. objects: {
  338. field: [{
  339. id: refId,
  340. value: "",
  341. actions: {
  342. Keystroke: [`event.change = "a";`]
  343. },
  344. type: "text"
  345. }]
  346. },
  347. appInfo: {
  348. language: "en-US",
  349. platform: "Linux x86_64"
  350. },
  351. calculationOrder: []
  352. };
  353. sandbox.createSandbox(data);
  354. await sandbox.dispatchEventInSandbox({
  355. id: refId,
  356. value: "hell",
  357. name: "Keystroke",
  358. willCommit: false,
  359. change: "o",
  360. selStart: 4,
  361. selEnd: 4
  362. });
  363. expect(send_queue.has(refId)).toEqual(true);
  364. expect(send_queue.get(refId)).toEqual({
  365. id: refId,
  366. value: "hella",
  367. selRange: [5, 5]
  368. });
  369. });
  370. it("should trigger an invalid commit Keystroke event", async () => {
  371. const refId = getId();
  372. const data = {
  373. objects: {
  374. field: [{
  375. id: refId,
  376. value: "",
  377. actions: {
  378. test: [`event.rc = false;`]
  379. },
  380. type: "text"
  381. }]
  382. },
  383. appInfo: {
  384. language: "en-US",
  385. platform: "Linux x86_64"
  386. },
  387. calculationOrder: []
  388. };
  389. sandbox.createSandbox(data);
  390. await sandbox.dispatchEventInSandbox({
  391. id: refId,
  392. value: "",
  393. name: "test",
  394. willCommit: true
  395. });
  396. expect(send_queue.has(refId)).toEqual(false);
  397. });
  398. it("should trigger a valid commit Keystroke event", async () => {
  399. const refId1 = getId();
  400. const refId2 = getId();
  401. const data = {
  402. objects: {
  403. field1: [{
  404. id: refId1,
  405. value: "",
  406. actions: {
  407. Validate: [`event.value = "world";`]
  408. },
  409. type: "text"
  410. }],
  411. field2: [{
  412. id: refId2,
  413. value: "",
  414. actions: {
  415. Calculate: [`event.value = "hello";`]
  416. },
  417. type: "text"
  418. }]
  419. },
  420. appInfo: {
  421. language: "en-US",
  422. platform: "Linux x86_64"
  423. },
  424. calculationOrder: [refId2]
  425. };
  426. sandbox.createSandbox(data);
  427. await sandbox.dispatchEventInSandbox({
  428. id: refId1,
  429. value: "hello",
  430. name: "Keystroke",
  431. willCommit: true
  432. });
  433. expect(send_queue.has(refId1)).toEqual(true);
  434. expect(send_queue.get(refId1)).toEqual({
  435. id: refId1,
  436. value: "world",
  437. formattedValue: null
  438. });
  439. });
  440. });
  441. describe("Color", function () {
  442. beforeAll(function () {
  443. sandbox.createSandbox({
  444. appInfo: {
  445. language: "en-US",
  446. platform: "Linux x86_64"
  447. },
  448. objects: {},
  449. calculationOrder: []
  450. });
  451. });
  452. function round(color) {
  453. return [color[0], ...color.slice(1).map(x => Math.round(x * 1000) / 1000)];
  454. }
  455. it("should convert RGB color for different color spaces", async () => {
  456. let value = await myeval(`color.convert(["RGB", 0.1, 0.2, 0.3], "T")`);
  457. expect(round(value)).toEqual(["T"]);
  458. value = await myeval(`color.convert(["RGB", 0.1, 0.2, 0.3], "G")`);
  459. expect(round(value)).toEqual(["G", 0.181]);
  460. value = await myeval(`color.convert(["RGB", 0.1, 0.2, 0.3], "RGB")`);
  461. expect(round(value)).toEqual(["RGB", 0.1, 0.2, 0.3]);
  462. value = await myeval(`color.convert(["RGB", 0.1, 0.2, 0.3], "CMYK")`);
  463. expect(round(value)).toEqual(["CMYK", 0.9, 0.8, 0.7, 0.7]);
  464. });
  465. it("should convert CMYK color for different color spaces", async () => {
  466. let value = await myeval(`color.convert(["CMYK", 0.1, 0.2, 0.3, 0.4], "T")`);
  467. expect(round(value)).toEqual(["T"]);
  468. value = await myeval(`color.convert(["CMYK", 0.1, 0.2, 0.3, 0.4], "G")`);
  469. expect(round(value)).toEqual(["G", 0.371]);
  470. value = await myeval(`color.convert(["CMYK", 0.1, 0.2, 0.3, 0.4], "RGB")`);
  471. expect(round(value)).toEqual(["RGB", 0.5, 0.3, 0.4]);
  472. value = await myeval(`color.convert(["CMYK", 0.1, 0.2, 0.3, 0.4], "CMYK")`);
  473. expect(round(value)).toEqual(["CMYK", 0.1, 0.2, 0.3, 0.4]);
  474. });
  475. it("should convert Gray color for different color spaces", async () => {
  476. let value = await myeval(`color.convert(["G", 0.1], "T")`);
  477. expect(round(value)).toEqual(["T"]);
  478. value = await myeval(`color.convert(["G", 0.1], "G")`);
  479. expect(round(value)).toEqual(["G", 0.1]);
  480. value = await myeval(`color.convert(["G", 0.1], "RGB")`);
  481. expect(round(value)).toEqual(["RGB", 0.1, 0.1, 0.1]);
  482. value = await myeval(`color.convert(["G", 0.1], "CMYK")`);
  483. expect(round(value)).toEqual(["CMYK", 0, 0, 0, 0.9]);
  484. });
  485. it("should convert Transparent color for different color spaces", async () => {
  486. let value = await myeval(`color.convert(["T"], "T")`);
  487. expect(round(value)).toEqual(["T"]);
  488. value = await myeval(`color.convert(["T"], "G")`);
  489. expect(round(value)).toEqual(["G", 0]);
  490. value = await myeval(`color.convert(["T"], "RGB")`);
  491. expect(round(value)).toEqual(["RGB", 0, 0, 0]);
  492. value = await myeval(`color.convert(["T"], "CMYK")`);
  493. expect(round(value)).toEqual(["CMYK", 0, 0, 0, 1]);
  494. });
  495. });
  496. describe("App", function () {
  497. beforeAll(function () {
  498. sandbox.createSandbox({
  499. appInfo: {
  500. language: "en-US",
  501. platform: "Linux x86_64"
  502. },
  503. objects: {},
  504. calculationOrder: []
  505. });
  506. });
  507. it("should test language", async () => {
  508. let value = await myeval(`app.language`);
  509. expect(value).toEqual("ENU");
  510. value = await myeval(`app.language = "hello"`);
  511. expect(value).toEqual("app.language is read-only");
  512. });
  513. it("should test platform", async () => {
  514. let value = await myeval(`app.platform`);
  515. expect(value).toEqual("UNIX");
  516. value = await myeval(`app.platform = "hello"`);
  517. expect(value).toEqual("app.platform is read-only");
  518. });
  519. });
  520. describe("AForm", function () {
  521. beforeAll(function () {
  522. sandbox.createSandbox({
  523. appInfo: {
  524. language: "en-US",
  525. platform: "Linux x86_64"
  526. },
  527. objects: {},
  528. calculationOrder: [],
  529. dispatchEventName: "_dispatchMe"
  530. });
  531. });
  532. describe("AFParseDateEx", function () {
  533. it("should parse a date with a format", async () => {
  534. const check = async (date, format, expected) => {
  535. const value = await myeval(`AFParseDateEx("${date}", "${format}").toISOString()`);
  536. expect(value).toEqual(new Date(expected).toISOString());
  537. };
  538. await check("05", "dd", "2000/01/05");
  539. await check("12", "mm", "2000/12/01");
  540. await check("2022", "yyyy", "2022/01/01");
  541. });
  542. });
  543. describe("AFExtractNums", function () {
  544. it("should extract numbers", async () => {
  545. let value = await myeval(`AFExtractNums("123 456 789")`);
  546. expect(value).toEqual(["123", "456", "789"]);
  547. value = await myeval(`AFExtractNums("123.456")`);
  548. expect(value).toEqual(["123", "456"]);
  549. value = await myeval(`AFExtractNums("123")`);
  550. expect(value).toEqual(["123"]);
  551. value = await myeval(`AFExtractNums(".123")`);
  552. expect(value).toEqual(["0", "123"]);
  553. value = await myeval(`AFExtractNums(",123")`);
  554. expect(value).toEqual(["0", "123"]);
  555. });
  556. });
  557. describe("AFMakeNumber", function () {
  558. it("should convert string to number", async () => {
  559. let value = await myeval(`AFMakeNumber("123.456")`);
  560. expect(value).toEqual(123.456);
  561. value = await myeval(`AFMakeNumber(123.456)`);
  562. expect(value).toEqual(123.456);
  563. value = await myeval(`AFMakeNumber("-123.456")`);
  564. expect(value).toEqual(-123.456);
  565. value = await myeval(`AFMakeNumber("-123,456")`);
  566. expect(value).toEqual(-123.456);
  567. value = await myeval(`AFMakeNumber("not a number")`);
  568. expect(value).toEqual(null);
  569. });
  570. });
  571. describe("AFMakeArrayFromList", function () {
  572. it("should split a string into an array of strings", async () => {
  573. const value = await myeval(`AFMakeArrayFromList("aaaa, bbbbbbb,cc,ddd, e")`);
  574. expect(value).toEqual(["aaaa", " bbbbbbb", "cc", "ddd", "e"]);
  575. });
  576. });
  577. describe("AFNumber_format", function () {
  578. it("should format a number", async () => {
  579. const refId = getId();
  580. const data = {
  581. objects: {
  582. field: [{
  583. id: refId,
  584. value: "",
  585. actions: {
  586. test1: [`AFNumber_Format(2, 0, 0, 0, "€", false);` + `event.source.value = event.value;`],
  587. test2: [`AFNumber_Format(1, 3, 0, 0, "$", true);` + `event.source.value = event.value;`],
  588. test3: [`AFNumber_Format(2, 0, 1, 0, "€", false);` + `event.source.value = event.value;`],
  589. test4: [`AFNumber_Format(2, 0, 2, 0, "€", false);` + `event.source.value = event.value;`],
  590. test5: [`AFNumber_Format(2, 0, 3, 0, "€", false);` + `event.source.value = event.value;`]
  591. },
  592. type: "text"
  593. }]
  594. },
  595. appInfo: {
  596. language: "en-US",
  597. platform: "Linux x86_64"
  598. },
  599. calculationOrder: [],
  600. dispatchEventName: "_dispatchMe"
  601. };
  602. sandbox.createSandbox(data);
  603. await sandbox.dispatchEventInSandbox({
  604. id: refId,
  605. value: "123456.789",
  606. name: "test1"
  607. });
  608. expect(send_queue.has(refId)).toEqual(true);
  609. expect(send_queue.get(refId)).toEqual({
  610. id: refId,
  611. value: "123,456.79€"
  612. });
  613. send_queue.delete(refId);
  614. await sandbox.dispatchEventInSandbox({
  615. id: refId,
  616. value: "223456.789",
  617. name: "test2"
  618. });
  619. expect(send_queue.has(refId)).toEqual(true);
  620. expect(send_queue.get(refId)).toEqual({
  621. id: refId,
  622. value: "$223456,8"
  623. });
  624. send_queue.delete(refId);
  625. await sandbox.dispatchEventInSandbox({
  626. id: refId,
  627. value: "-323456.789",
  628. name: "test3"
  629. });
  630. expect(send_queue.has(refId)).toEqual(true);
  631. expect(send_queue.get(refId)).toEqual({
  632. id: refId,
  633. value: "323,456.79€",
  634. textColor: ["RGB", 1, 0, 0]
  635. });
  636. send_queue.delete(refId);
  637. await sandbox.dispatchEventInSandbox({
  638. id: refId,
  639. value: "-423456.789",
  640. name: "test4"
  641. });
  642. expect(send_queue.has(refId)).toEqual(true);
  643. expect(send_queue.get(refId)).toEqual({
  644. id: refId,
  645. value: "(423,456.79€)"
  646. });
  647. send_queue.delete(refId);
  648. await sandbox.dispatchEventInSandbox({
  649. id: refId,
  650. value: "-52345.678",
  651. name: "test5"
  652. });
  653. expect(send_queue.has(refId)).toEqual(true);
  654. expect(send_queue.get(refId)).toEqual({
  655. id: refId,
  656. value: "(52,345.68€)",
  657. textColor: ["RGB", 1, 0, 0]
  658. });
  659. });
  660. });
  661. describe("AFNumber_Keystroke", function () {
  662. it("should validate a number on a keystroke event", async () => {
  663. const refId = getId();
  664. const data = {
  665. objects: {
  666. field: [{
  667. id: refId,
  668. value: "",
  669. actions: {
  670. Validate: [`AFNumber_Keystroke(null, 0, null, null, null, null);`]
  671. },
  672. type: "text",
  673. name: "MyField"
  674. }]
  675. },
  676. appInfo: {
  677. language: "en-US",
  678. platform: "Linux x86_64"
  679. },
  680. calculationOrder: [],
  681. dispatchEventName: "_dispatchMe"
  682. };
  683. sandbox.createSandbox(data);
  684. await sandbox.dispatchEventInSandbox({
  685. id: refId,
  686. value: "123456.789",
  687. name: "Keystroke",
  688. willCommit: true
  689. });
  690. expect(send_queue.has(refId)).toEqual(true);
  691. expect(send_queue.get(refId)).toEqual({
  692. id: refId,
  693. value: "123456.789",
  694. formattedValue: null
  695. });
  696. });
  697. it("should not validate a number on a keystroke event", async () => {
  698. const refId = getId();
  699. const data = {
  700. objects: {
  701. field: [{
  702. id: refId,
  703. value: "",
  704. actions: {
  705. Validate: [`AFNumber_Keystroke(null, 0, null, null, null, null);`]
  706. },
  707. type: "text",
  708. name: "MyField"
  709. }]
  710. },
  711. appInfo: {
  712. language: "en-US",
  713. platform: "Linux x86_64"
  714. },
  715. calculationOrder: [],
  716. dispatchEventName: "_dispatchMe"
  717. };
  718. sandbox.createSandbox(data);
  719. await sandbox.dispatchEventInSandbox({
  720. id: refId,
  721. value: "123s456.789",
  722. name: "Keystroke",
  723. willCommit: true
  724. });
  725. expect(send_queue.has("alert")).toEqual(true);
  726. expect(send_queue.get("alert")).toEqual({
  727. command: "alert",
  728. value: "The value entered does not match the format of the field [ MyField ]"
  729. });
  730. });
  731. });
  732. describe("AFPercent_Format", function () {
  733. it("should format a percentage", async () => {
  734. const refId = getId();
  735. const data = {
  736. objects: {
  737. field: [{
  738. id: refId,
  739. value: "",
  740. actions: {
  741. test1: [`AFPercent_Format(2, 1, false);` + `event.source.value = event.value;`],
  742. test2: [`AFPercent_Format(2, 1, true);` + `event.source.value = event.value;`]
  743. },
  744. type: "text"
  745. }]
  746. },
  747. appInfo: {
  748. language: "en-US",
  749. platform: "Linux x86_64"
  750. },
  751. calculationOrder: [],
  752. dispatchEventName: "_dispatchMe"
  753. };
  754. sandbox.createSandbox(data);
  755. await sandbox.dispatchEventInSandbox({
  756. id: refId,
  757. value: "0.456789",
  758. name: "test1"
  759. });
  760. expect(send_queue.has(refId)).toEqual(true);
  761. expect(send_queue.get(refId)).toEqual({
  762. id: refId,
  763. value: "45.68%"
  764. });
  765. send_queue.delete(refId);
  766. await sandbox.dispatchEventInSandbox({
  767. id: refId,
  768. value: "0.456789",
  769. name: "test2"
  770. });
  771. expect(send_queue.has(refId)).toEqual(true);
  772. expect(send_queue.get(refId)).toEqual({
  773. id: refId,
  774. value: "%45.68"
  775. });
  776. });
  777. });
  778. describe("AFDate_Format", function () {
  779. it("should format a date", async () => {
  780. const refId = getId();
  781. const data = {
  782. objects: {
  783. field: [{
  784. id: refId,
  785. value: "",
  786. actions: {
  787. test1: [`AFDate_Format(0);event.source.value = event.value;`],
  788. test2: [`AFDate_Format(12);event.source.value = event.value;`]
  789. },
  790. type: "text"
  791. }]
  792. },
  793. appInfo: {
  794. language: "en-US",
  795. platform: "Linux x86_64"
  796. },
  797. calculationOrder: [],
  798. dispatchEventName: "_dispatchMe"
  799. };
  800. sandbox.createSandbox(data);
  801. await sandbox.dispatchEventInSandbox({
  802. id: refId,
  803. value: "Sun Apr 15 2007 03:14:15",
  804. name: "test1"
  805. });
  806. expect(send_queue.has(refId)).toEqual(true);
  807. expect(send_queue.get(refId)).toEqual({
  808. id: refId,
  809. value: "4/15"
  810. });
  811. send_queue.delete(refId);
  812. await sandbox.dispatchEventInSandbox({
  813. id: refId,
  814. value: "Sun Apr 15 2007 03:14:15",
  815. name: "test2"
  816. });
  817. expect(send_queue.has(refId)).toEqual(true);
  818. expect(send_queue.get(refId)).toEqual({
  819. id: refId,
  820. value: "4/15/07 3:14 am"
  821. });
  822. });
  823. });
  824. describe("AFRange_Validate", function () {
  825. it("should validate a number in range [a, b]", async () => {
  826. const refId = getId();
  827. const data = {
  828. objects: {
  829. field: [{
  830. id: refId,
  831. value: "",
  832. actions: {
  833. Validate: [`AFRange_Validate(true, 123, true, 456);`]
  834. },
  835. type: "text"
  836. }]
  837. },
  838. appInfo: {
  839. language: "en-US",
  840. platform: "Linux x86_64"
  841. },
  842. calculationOrder: [],
  843. dispatchEventName: "_dispatchMe"
  844. };
  845. sandbox.createSandbox(data);
  846. await sandbox.dispatchEventInSandbox({
  847. id: refId,
  848. value: "321",
  849. name: "Keystroke",
  850. willCommit: true
  851. });
  852. expect(send_queue.has(refId)).toEqual(true);
  853. expect(send_queue.get(refId)).toEqual({
  854. id: refId,
  855. value: "321",
  856. formattedValue: null
  857. });
  858. });
  859. it("should invalidate a number out of range [a, b]", async () => {
  860. const refId = getId();
  861. const data = {
  862. objects: {
  863. field: [{
  864. id: refId,
  865. value: "",
  866. actions: {
  867. Validate: [`AFRange_Validate(true, 123, true, 456);`]
  868. },
  869. type: "text"
  870. }]
  871. },
  872. appInfo: {
  873. language: "en-US",
  874. platform: "Linux x86_64"
  875. },
  876. calculationOrder: [],
  877. dispatchEventName: "_dispatchMe"
  878. };
  879. sandbox.createSandbox(data);
  880. await sandbox.dispatchEventInSandbox({
  881. id: refId,
  882. value: "12",
  883. name: "Keystroke",
  884. willCommit: true
  885. });
  886. expect(send_queue.has("alert")).toEqual(true);
  887. expect(send_queue.get("alert")).toEqual({
  888. command: "alert",
  889. value: "Invalid value: must be greater than or equal to 123 and less than or equal to 456."
  890. });
  891. });
  892. });
  893. describe("ASSimple_Calculate", function () {
  894. it("should compute the sum of several fields", async () => {
  895. const refIds = [0, 1, 2, 3].map(_ => getId());
  896. const data = {
  897. objects: {
  898. field1: [{
  899. id: refIds[0],
  900. value: "",
  901. actions: {},
  902. type: "text"
  903. }],
  904. field2: [{
  905. id: refIds[1],
  906. value: "",
  907. actions: {},
  908. type: "text"
  909. }],
  910. field3: [{
  911. id: refIds[2],
  912. value: "",
  913. actions: {},
  914. type: "text"
  915. }],
  916. field4: [{
  917. id: refIds[3],
  918. value: "",
  919. actions: {
  920. Calculate: [`AFSimple_Calculate("SUM", ["field1", "field2", "field3"]);`]
  921. },
  922. type: "text"
  923. }]
  924. },
  925. appInfo: {
  926. language: "en-US",
  927. platform: "Linux x86_64"
  928. },
  929. calculationOrder: [refIds[3]],
  930. dispatchEventName: "_dispatchMe"
  931. };
  932. sandbox.createSandbox(data);
  933. await sandbox.dispatchEventInSandbox({
  934. id: refIds[0],
  935. value: "1",
  936. name: "Keystroke",
  937. willCommit: true
  938. });
  939. expect(send_queue.has(refIds[3])).toEqual(true);
  940. expect(send_queue.get(refIds[3])).toEqual({
  941. id: refIds[3],
  942. value: 1,
  943. formattedValue: null
  944. });
  945. await sandbox.dispatchEventInSandbox({
  946. id: refIds[1],
  947. value: "2",
  948. name: "Keystroke",
  949. willCommit: true
  950. });
  951. expect(send_queue.has(refIds[3])).toEqual(true);
  952. expect(send_queue.get(refIds[3])).toEqual({
  953. id: refIds[3],
  954. value: 3,
  955. formattedValue: null
  956. });
  957. await sandbox.dispatchEventInSandbox({
  958. id: refIds[2],
  959. value: "3",
  960. name: "Keystroke",
  961. willCommit: true
  962. });
  963. expect(send_queue.has(refIds[3])).toEqual(true);
  964. expect(send_queue.get(refIds[3])).toEqual({
  965. id: refIds[3],
  966. value: 6,
  967. formattedValue: null
  968. });
  969. });
  970. });
  971. describe("AFSpecial_KeystrokeEx", function () {
  972. it("should validate a phone number on a keystroke event", async () => {
  973. const refId = getId();
  974. const data = {
  975. objects: {
  976. field: [{
  977. id: refId,
  978. value: "",
  979. actions: {
  980. Keystroke: [`AFSpecial_KeystrokeEx("9AXO");`]
  981. },
  982. type: "text"
  983. }]
  984. },
  985. appInfo: {
  986. language: "en-US",
  987. platform: "Linux x86_64"
  988. },
  989. calculationOrder: [],
  990. dispatchEventName: "_dispatchMe"
  991. };
  992. sandbox.createSandbox(data);
  993. await sandbox.dispatchEventInSandbox({
  994. id: refId,
  995. value: "",
  996. change: "3",
  997. name: "Keystroke",
  998. willCommit: false,
  999. selStart: 0,
  1000. selEnd: 0
  1001. });
  1002. expect(send_queue.has(refId)).toEqual(true);
  1003. send_queue.delete(refId);
  1004. await sandbox.dispatchEventInSandbox({
  1005. id: refId,
  1006. value: "3",
  1007. change: "F",
  1008. name: "Keystroke",
  1009. willCommit: false,
  1010. selStart: 1,
  1011. selEnd: 1
  1012. });
  1013. expect(send_queue.has(refId)).toEqual(true);
  1014. send_queue.delete(refId);
  1015. await sandbox.dispatchEventInSandbox({
  1016. id: refId,
  1017. value: "3F",
  1018. change: "?",
  1019. name: "Keystroke",
  1020. willCommit: false,
  1021. selStart: 2,
  1022. selEnd: 2
  1023. });
  1024. expect(send_queue.has(refId)).toEqual(true);
  1025. send_queue.delete(refId);
  1026. await sandbox.dispatchEventInSandbox({
  1027. id: refId,
  1028. value: "3F?",
  1029. change: "@",
  1030. name: "Keystroke",
  1031. willCommit: false,
  1032. selStart: 3,
  1033. selEnd: 3
  1034. });
  1035. expect(send_queue.has(refId)).toEqual(true);
  1036. expect(send_queue.get(refId)).toEqual({
  1037. id: refId,
  1038. value: "3F?",
  1039. selRange: [3, 3]
  1040. });
  1041. send_queue.delete(refId);
  1042. await sandbox.dispatchEventInSandbox({
  1043. id: refId,
  1044. value: "3F?",
  1045. change: "0",
  1046. name: "Keystroke",
  1047. willCommit: false,
  1048. selStart: 3,
  1049. selEnd: 3
  1050. });
  1051. expect(send_queue.has(refId)).toEqual(true);
  1052. send_queue.delete(refId);
  1053. await sandbox.dispatchEventInSandbox({
  1054. id: refId,
  1055. value: "3F?0",
  1056. name: "Keystroke",
  1057. willCommit: true,
  1058. selStart: 4,
  1059. selEnd: 4
  1060. });
  1061. expect(send_queue.has(refId)).toEqual(true);
  1062. expect(send_queue.get(refId)).toEqual({
  1063. id: refId,
  1064. value: "3F?0",
  1065. formattedValue: null
  1066. });
  1067. });
  1068. });
  1069. describe("AFSpecial_Keystroke", function () {
  1070. it("should validate a zip code on a keystroke event", async () => {
  1071. const refId = getId();
  1072. const data = {
  1073. objects: {
  1074. field: [{
  1075. id: refId,
  1076. value: "",
  1077. actions: {
  1078. Keystroke: [`AFSpecial_Keystroke(0);`]
  1079. },
  1080. type: "text"
  1081. }]
  1082. },
  1083. appInfo: {
  1084. language: "en-US",
  1085. platform: "Linux x86_64"
  1086. },
  1087. calculationOrder: [],
  1088. dispatchEventName: "_dispatchMe"
  1089. };
  1090. sandbox.createSandbox(data);
  1091. let value = "";
  1092. const changes = "12345";
  1093. let i = 0;
  1094. for (; i < changes.length; i++) {
  1095. const change = changes.charAt(i);
  1096. await sandbox.dispatchEventInSandbox({
  1097. id: refId,
  1098. value,
  1099. change,
  1100. name: "Keystroke",
  1101. willCommit: false,
  1102. selStart: i,
  1103. selEnd: i
  1104. });
  1105. expect(send_queue.has(refId)).toEqual(true);
  1106. send_queue.delete(refId);
  1107. value += change;
  1108. }
  1109. await sandbox.dispatchEventInSandbox({
  1110. id: refId,
  1111. value,
  1112. change: "A",
  1113. name: "Keystroke",
  1114. willCommit: false,
  1115. selStart: i,
  1116. selEnd: i
  1117. });
  1118. expect(send_queue.has(refId)).toEqual(true);
  1119. expect(send_queue.get(refId)).toEqual({
  1120. id: refId,
  1121. value,
  1122. selRange: [i, i]
  1123. });
  1124. send_queue.delete(refId);
  1125. });
  1126. it("should validate a US phone number (long) on a keystroke event", async () => {
  1127. const refId = getId();
  1128. const data = {
  1129. objects: {
  1130. field: [{
  1131. id: refId,
  1132. value: "",
  1133. actions: {
  1134. Keystroke: [`AFSpecial_Keystroke(2);`]
  1135. },
  1136. type: "text"
  1137. }]
  1138. },
  1139. appInfo: {
  1140. language: "en-US",
  1141. platform: "Linux x86_64"
  1142. },
  1143. calculationOrder: [],
  1144. dispatchEventName: "_dispatchMe"
  1145. };
  1146. sandbox.createSandbox(data);
  1147. let value = "";
  1148. const changes = "(123) 456-7890";
  1149. let i = 0;
  1150. for (; i < changes.length; i++) {
  1151. const change = changes.charAt(i);
  1152. await sandbox.dispatchEventInSandbox({
  1153. id: refId,
  1154. value,
  1155. change,
  1156. name: "Keystroke",
  1157. willCommit: false,
  1158. selStart: i,
  1159. selEnd: i
  1160. });
  1161. expect(send_queue.has(refId)).toEqual(true);
  1162. send_queue.delete(refId);
  1163. value += change;
  1164. }
  1165. await sandbox.dispatchEventInSandbox({
  1166. id: refId,
  1167. value,
  1168. change: "A",
  1169. name: "Keystroke",
  1170. willCommit: false,
  1171. selStart: i,
  1172. selEnd: i
  1173. });
  1174. expect(send_queue.has(refId)).toEqual(true);
  1175. expect(send_queue.get(refId)).toEqual({
  1176. id: refId,
  1177. value,
  1178. selRange: [i, i]
  1179. });
  1180. send_queue.delete(refId);
  1181. });
  1182. it("should validate a US phone number (short) on a keystroke event", async () => {
  1183. const refId = getId();
  1184. const data = {
  1185. objects: {
  1186. field: [{
  1187. id: refId,
  1188. value: "",
  1189. actions: {
  1190. Keystroke: [`AFSpecial_Keystroke(2);`]
  1191. },
  1192. type: "text"
  1193. }]
  1194. },
  1195. appInfo: {
  1196. language: "en-US",
  1197. platform: "Linux x86_64"
  1198. },
  1199. calculationOrder: [],
  1200. dispatchEventName: "_dispatchMe"
  1201. };
  1202. sandbox.createSandbox(data);
  1203. let value = "";
  1204. const changes = "123-4567";
  1205. let i = 0;
  1206. for (; i < changes.length; i++) {
  1207. const change = changes.charAt(i);
  1208. await sandbox.dispatchEventInSandbox({
  1209. id: refId,
  1210. value,
  1211. change,
  1212. name: "Keystroke",
  1213. willCommit: false,
  1214. selStart: i,
  1215. selEnd: i
  1216. });
  1217. expect(send_queue.has(refId)).toEqual(true);
  1218. send_queue.delete(refId);
  1219. value += change;
  1220. }
  1221. await sandbox.dispatchEventInSandbox({
  1222. id: refId,
  1223. value,
  1224. change: "A",
  1225. name: "Keystroke",
  1226. willCommit: false,
  1227. selStart: i,
  1228. selEnd: i
  1229. });
  1230. expect(send_queue.has(refId)).toEqual(true);
  1231. expect(send_queue.get(refId)).toEqual({
  1232. id: refId,
  1233. value,
  1234. selRange: [i, i]
  1235. });
  1236. send_queue.delete(refId);
  1237. });
  1238. });
  1239. describe("eMailValidate", function () {
  1240. it("should validate an e-mail address", async () => {
  1241. let value = await myeval(`eMailValidate(123)`);
  1242. expect(value).toEqual(false);
  1243. value = await myeval(`eMailValidate("foo@bar.com")`);
  1244. expect(value).toEqual(true);
  1245. value = await myeval(`eMailValidate("foo bar")`);
  1246. expect(value).toEqual(false);
  1247. });
  1248. });
  1249. });
  1250. });