scripting_spec.js 39 KB

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