scripting_spec.js 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2021 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 (done) {
  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. done();
  79. });
  80. afterAll(function () {
  81. sandbox.nukeSandbox();
  82. sandbox = null;
  83. send_queue = null;
  84. window.alert = windowAlert;
  85. });
  86. describe("Sandbox", function () {
  87. it("should send a value, execute an action and get back a new value", async () => {
  88. function compute(n) {
  89. let s = 0;
  90. for (let i = 0; i < n; i++) {
  91. s += i;
  92. }
  93. return s;
  94. }
  95. const number = 123;
  96. const expected = ((number - 1) * number / 2).toString();
  97. const refId = getId();
  98. const data = {
  99. objects: {
  100. field: [{
  101. id: refId,
  102. value: "",
  103. actions: {
  104. Keystroke: [`${compute.toString()}event.value = compute(parseInt(event.value));`]
  105. },
  106. type: "text"
  107. }]
  108. },
  109. calculationOrder: [],
  110. appInfo: {
  111. language: "en-US",
  112. platform: "Linux x86_64"
  113. }
  114. };
  115. sandbox.createSandbox(data);
  116. await sandbox.dispatchEventInSandbox({
  117. id: refId,
  118. value: `${number}`,
  119. name: "Keystroke",
  120. willCommit: true
  121. });
  122. expect(send_queue.has(refId)).toEqual(true);
  123. expect(send_queue.get(refId)).toEqual({
  124. id: refId,
  125. valueAsString: expected
  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 (done) {
  199. sandbox.createSandbox({
  200. appInfo: {
  201. language: "en-US",
  202. platform: "Linux x86_64"
  203. },
  204. objects: {},
  205. calculationOrder: []
  206. });
  207. done();
  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. value: "hell",
  332. selRange: [4, 4]
  333. });
  334. });
  335. it("should trigger a Keystroke event and change it", async () => {
  336. const refId = getId();
  337. const data = {
  338. objects: {
  339. field: [{
  340. id: refId,
  341. value: "",
  342. actions: {
  343. Keystroke: [`event.change = "a";`]
  344. },
  345. type: "text"
  346. }]
  347. },
  348. appInfo: {
  349. language: "en-US",
  350. platform: "Linux x86_64"
  351. },
  352. calculationOrder: []
  353. };
  354. sandbox.createSandbox(data);
  355. await sandbox.dispatchEventInSandbox({
  356. id: refId,
  357. value: "hell",
  358. name: "Keystroke",
  359. willCommit: false,
  360. change: "o",
  361. selStart: 4,
  362. selEnd: 4
  363. });
  364. expect(send_queue.has(refId)).toEqual(true);
  365. expect(send_queue.get(refId)).toEqual({
  366. id: refId,
  367. value: "hella"
  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. valueAsString: "world"
  438. });
  439. });
  440. });
  441. describe("Color", function () {
  442. beforeAll(function (done) {
  443. sandbox.createSandbox({
  444. appInfo: {
  445. language: "en-US",
  446. platform: "Linux x86_64"
  447. },
  448. objects: {},
  449. calculationOrder: []
  450. });
  451. done();
  452. });
  453. function round(color) {
  454. return [color[0], ...color.slice(1).map(x => Math.round(x * 1000) / 1000)];
  455. }
  456. it("should convert RGB color for different color spaces", async () => {
  457. let value = await myeval(`color.convert(["RGB", 0.1, 0.2, 0.3], "T")`);
  458. expect(round(value)).toEqual(["T"]);
  459. value = await myeval(`color.convert(["RGB", 0.1, 0.2, 0.3], "G")`);
  460. expect(round(value)).toEqual(["G", 0.181]);
  461. value = await myeval(`color.convert(["RGB", 0.1, 0.2, 0.3], "RGB")`);
  462. expect(round(value)).toEqual(["RGB", 0.1, 0.2, 0.3]);
  463. value = await myeval(`color.convert(["RGB", 0.1, 0.2, 0.3], "CMYK")`);
  464. expect(round(value)).toEqual(["CMYK", 0.9, 0.8, 0.7, 0.7]);
  465. });
  466. it("should convert CMYK color for different color spaces", async () => {
  467. let value = await myeval(`color.convert(["CMYK", 0.1, 0.2, 0.3, 0.4], "T")`);
  468. expect(round(value)).toEqual(["T"]);
  469. value = await myeval(`color.convert(["CMYK", 0.1, 0.2, 0.3, 0.4], "G")`);
  470. expect(round(value)).toEqual(["G", 0.371]);
  471. value = await myeval(`color.convert(["CMYK", 0.1, 0.2, 0.3, 0.4], "RGB")`);
  472. expect(round(value)).toEqual(["RGB", 0.5, 0.3, 0.4]);
  473. value = await myeval(`color.convert(["CMYK", 0.1, 0.2, 0.3, 0.4], "CMYK")`);
  474. expect(round(value)).toEqual(["CMYK", 0.1, 0.2, 0.3, 0.4]);
  475. });
  476. it("should convert Gray color for different color spaces", async () => {
  477. let value = await myeval(`color.convert(["G", 0.1], "T")`);
  478. expect(round(value)).toEqual(["T"]);
  479. value = await myeval(`color.convert(["G", 0.1], "G")`);
  480. expect(round(value)).toEqual(["G", 0.1]);
  481. value = await myeval(`color.convert(["G", 0.1], "RGB")`);
  482. expect(round(value)).toEqual(["RGB", 0.1, 0.1, 0.1]);
  483. value = await myeval(`color.convert(["G", 0.1], "CMYK")`);
  484. expect(round(value)).toEqual(["CMYK", 0, 0, 0, 0.9]);
  485. });
  486. it("should convert Transparent color for different color spaces", async () => {
  487. let value = await myeval(`color.convert(["T"], "T")`);
  488. expect(round(value)).toEqual(["T"]);
  489. value = await myeval(`color.convert(["T"], "G")`);
  490. expect(round(value)).toEqual(["G", 0]);
  491. value = await myeval(`color.convert(["T"], "RGB")`);
  492. expect(round(value)).toEqual(["RGB", 0, 0, 0]);
  493. value = await myeval(`color.convert(["T"], "CMYK")`);
  494. expect(round(value)).toEqual(["CMYK", 0, 0, 0, 1]);
  495. });
  496. });
  497. describe("App", function () {
  498. beforeAll(function (done) {
  499. sandbox.createSandbox({
  500. appInfo: {
  501. language: "en-US",
  502. platform: "Linux x86_64"
  503. },
  504. objects: {},
  505. calculationOrder: []
  506. });
  507. done();
  508. });
  509. it("should test language", async () => {
  510. let value = await myeval(`app.language`);
  511. expect(value).toEqual("ENU");
  512. value = await myeval(`app.language = "hello"`);
  513. expect(value).toEqual("app.language is read-only");
  514. });
  515. it("should test platform", async () => {
  516. let value = await myeval(`app.platform`);
  517. expect(value).toEqual("UNIX");
  518. value = await myeval(`app.platform = "hello"`);
  519. expect(value).toEqual("app.platform is read-only");
  520. });
  521. });
  522. describe("AForm", function () {
  523. beforeAll(function (done) {
  524. sandbox.createSandbox({
  525. appInfo: {
  526. language: "en-US",
  527. platform: "Linux x86_64"
  528. },
  529. objects: {},
  530. calculationOrder: [],
  531. dispatchEventName: "_dispatchMe"
  532. });
  533. done();
  534. });
  535. describe("AFExtractNums", function () {
  536. it("should extract numbers", async () => {
  537. let value = await myeval(`AFExtractNums("123 456 789")`);
  538. expect(value).toEqual(["123", "456", "789"]);
  539. value = await myeval(`AFExtractNums("123.456")`);
  540. expect(value).toEqual(["123", "456"]);
  541. value = await myeval(`AFExtractNums("123")`);
  542. expect(value).toEqual(["123"]);
  543. value = await myeval(`AFExtractNums(".123")`);
  544. expect(value).toEqual(["0", "123"]);
  545. value = await myeval(`AFExtractNums(",123")`);
  546. expect(value).toEqual(["0", "123"]);
  547. });
  548. });
  549. describe("AFMakeNumber", function () {
  550. it("should convert string to number", async () => {
  551. let value = await myeval(`AFMakeNumber("123.456")`);
  552. expect(value).toEqual(123.456);
  553. value = await myeval(`AFMakeNumber(123.456)`);
  554. expect(value).toEqual(123.456);
  555. value = await myeval(`AFMakeNumber("-123.456")`);
  556. expect(value).toEqual(-123.456);
  557. value = await myeval(`AFMakeNumber("-123,456")`);
  558. expect(value).toEqual(-123.456);
  559. value = await myeval(`AFMakeNumber("not a number")`);
  560. expect(value).toEqual(null);
  561. });
  562. });
  563. describe("AFMakeArrayFromList", function () {
  564. it("should split a string into an array of strings", async () => {
  565. const value = await myeval(`AFMakeArrayFromList("aaaa, bbbbbbb,cc,ddd, e")`);
  566. expect(value).toEqual(["aaaa", " bbbbbbb", "cc", "ddd", "e"]);
  567. });
  568. });
  569. describe("AFNumber_format", function () {
  570. it("should format a number", async () => {
  571. const refId = getId();
  572. const data = {
  573. objects: {
  574. field: [{
  575. id: refId,
  576. value: "",
  577. actions: {
  578. test1: [`AFNumber_Format(2, 0, 0, 0, "€", false);` + `event.source.value = event.value;`],
  579. test2: [`AFNumber_Format(1, 3, 0, 0, "$", true);` + `event.source.value = event.value;`],
  580. test3: [`AFNumber_Format(2, 0, 1, 0, "€", false);` + `event.source.value = event.value;`],
  581. test4: [`AFNumber_Format(2, 0, 2, 0, "€", false);` + `event.source.value = event.value;`],
  582. test5: [`AFNumber_Format(2, 0, 3, 0, "€", false);` + `event.source.value = event.value;`]
  583. },
  584. type: "text"
  585. }]
  586. },
  587. appInfo: {
  588. language: "en-US",
  589. platform: "Linux x86_64"
  590. },
  591. calculationOrder: [],
  592. dispatchEventName: "_dispatchMe"
  593. };
  594. sandbox.createSandbox(data);
  595. await sandbox.dispatchEventInSandbox({
  596. id: refId,
  597. value: "123456.789",
  598. name: "test1"
  599. });
  600. expect(send_queue.has(refId)).toEqual(true);
  601. expect(send_queue.get(refId)).toEqual({
  602. id: refId,
  603. value: "123,456.79€"
  604. });
  605. send_queue.delete(refId);
  606. await sandbox.dispatchEventInSandbox({
  607. id: refId,
  608. value: "223456.789",
  609. name: "test2"
  610. });
  611. expect(send_queue.has(refId)).toEqual(true);
  612. expect(send_queue.get(refId)).toEqual({
  613. id: refId,
  614. value: "$223456,8"
  615. });
  616. send_queue.delete(refId);
  617. await sandbox.dispatchEventInSandbox({
  618. id: refId,
  619. value: "-323456.789",
  620. name: "test3"
  621. });
  622. expect(send_queue.has(refId)).toEqual(true);
  623. expect(send_queue.get(refId)).toEqual({
  624. id: refId,
  625. value: "323,456.79€",
  626. textColor: ["RGB", 1, 0, 0]
  627. });
  628. send_queue.delete(refId);
  629. await sandbox.dispatchEventInSandbox({
  630. id: refId,
  631. value: "-423456.789",
  632. name: "test4"
  633. });
  634. expect(send_queue.has(refId)).toEqual(true);
  635. expect(send_queue.get(refId)).toEqual({
  636. id: refId,
  637. value: "(423,456.79€)"
  638. });
  639. send_queue.delete(refId);
  640. await sandbox.dispatchEventInSandbox({
  641. id: refId,
  642. value: "-52345.678",
  643. name: "test5"
  644. });
  645. expect(send_queue.has(refId)).toEqual(true);
  646. expect(send_queue.get(refId)).toEqual({
  647. id: refId,
  648. value: "(52,345.68€)",
  649. textColor: ["RGB", 1, 0, 0]
  650. });
  651. });
  652. });
  653. describe("AFNumber_Keystroke", function () {
  654. it("should validate a number on a keystroke event", async () => {
  655. const refId = getId();
  656. const data = {
  657. objects: {
  658. field: [{
  659. id: refId,
  660. value: "",
  661. actions: {
  662. Validate: [`AFNumber_Keystroke(null, 0, null, null, null, null);`]
  663. },
  664. type: "text",
  665. name: "MyField"
  666. }]
  667. },
  668. appInfo: {
  669. language: "en-US",
  670. platform: "Linux x86_64"
  671. },
  672. calculationOrder: [],
  673. dispatchEventName: "_dispatchMe"
  674. };
  675. sandbox.createSandbox(data);
  676. await sandbox.dispatchEventInSandbox({
  677. id: refId,
  678. value: "123456.789",
  679. name: "Keystroke",
  680. willCommit: true
  681. });
  682. expect(send_queue.has(refId)).toEqual(true);
  683. expect(send_queue.get(refId)).toEqual({
  684. id: refId,
  685. value: "123456.789",
  686. valueAsString: "123456.789"
  687. });
  688. });
  689. it("should not validate a number on a keystroke event", async () => {
  690. const refId = getId();
  691. const data = {
  692. objects: {
  693. field: [{
  694. id: refId,
  695. value: "",
  696. actions: {
  697. Validate: [`AFNumber_Keystroke(null, 0, null, null, null, null);`]
  698. },
  699. type: "text",
  700. name: "MyField"
  701. }]
  702. },
  703. appInfo: {
  704. language: "en-US",
  705. platform: "Linux x86_64"
  706. },
  707. calculationOrder: [],
  708. dispatchEventName: "_dispatchMe"
  709. };
  710. sandbox.createSandbox(data);
  711. await sandbox.dispatchEventInSandbox({
  712. id: refId,
  713. value: "123s456.789",
  714. name: "Keystroke",
  715. willCommit: true
  716. });
  717. expect(send_queue.has("alert")).toEqual(true);
  718. expect(send_queue.get("alert")).toEqual({
  719. command: "alert",
  720. value: "The value entered does not match the format of the field [ MyField ]"
  721. });
  722. });
  723. });
  724. describe("AFPercent_Format", function () {
  725. it("should format a percentage", async () => {
  726. const refId = getId();
  727. const data = {
  728. objects: {
  729. field: [{
  730. id: refId,
  731. value: "",
  732. actions: {
  733. test1: [`AFPercent_Format(2, 1, false);` + `event.source.value = event.value;`],
  734. test2: [`AFPercent_Format(2, 1, true);` + `event.source.value = event.value;`]
  735. },
  736. type: "text"
  737. }]
  738. },
  739. appInfo: {
  740. language: "en-US",
  741. platform: "Linux x86_64"
  742. },
  743. calculationOrder: [],
  744. dispatchEventName: "_dispatchMe"
  745. };
  746. sandbox.createSandbox(data);
  747. await sandbox.dispatchEventInSandbox({
  748. id: refId,
  749. value: "0.456789",
  750. name: "test1"
  751. });
  752. expect(send_queue.has(refId)).toEqual(true);
  753. expect(send_queue.get(refId)).toEqual({
  754. id: refId,
  755. value: "45.68%"
  756. });
  757. send_queue.delete(refId);
  758. await sandbox.dispatchEventInSandbox({
  759. id: refId,
  760. value: "0.456789",
  761. name: "test2"
  762. });
  763. expect(send_queue.has(refId)).toEqual(true);
  764. expect(send_queue.get(refId)).toEqual({
  765. id: refId,
  766. value: "%45.68"
  767. });
  768. });
  769. });
  770. describe("AFDate_Format", function () {
  771. it("should format a date", async () => {
  772. const refId = getId();
  773. const data = {
  774. objects: {
  775. field: [{
  776. id: refId,
  777. value: "",
  778. actions: {
  779. test1: [`AFDate_Format(0);event.source.value = event.value;`],
  780. test2: [`AFDate_Format(12);event.source.value = event.value;`]
  781. },
  782. type: "text"
  783. }]
  784. },
  785. appInfo: {
  786. language: "en-US",
  787. platform: "Linux x86_64"
  788. },
  789. calculationOrder: [],
  790. dispatchEventName: "_dispatchMe"
  791. };
  792. sandbox.createSandbox(data);
  793. await sandbox.dispatchEventInSandbox({
  794. id: refId,
  795. value: "Sun Apr 15 2007 03:14:15",
  796. name: "test1"
  797. });
  798. expect(send_queue.has(refId)).toEqual(true);
  799. expect(send_queue.get(refId)).toEqual({
  800. id: refId,
  801. value: "4/15"
  802. });
  803. send_queue.delete(refId);
  804. await sandbox.dispatchEventInSandbox({
  805. id: refId,
  806. value: "Sun Apr 15 2007 03:14:15",
  807. name: "test2"
  808. });
  809. expect(send_queue.has(refId)).toEqual(true);
  810. expect(send_queue.get(refId)).toEqual({
  811. id: refId,
  812. value: "4/15/07 3:14 am"
  813. });
  814. });
  815. });
  816. describe("AFRange_Validate", function () {
  817. it("should validate a number in range [a, b]", async () => {
  818. const refId = getId();
  819. const data = {
  820. objects: {
  821. field: [{
  822. id: refId,
  823. value: "",
  824. actions: {
  825. Validate: [`AFRange_Validate(true, 123, true, 456);`]
  826. },
  827. type: "text"
  828. }]
  829. },
  830. appInfo: {
  831. language: "en-US",
  832. platform: "Linux x86_64"
  833. },
  834. calculationOrder: [],
  835. dispatchEventName: "_dispatchMe"
  836. };
  837. sandbox.createSandbox(data);
  838. await sandbox.dispatchEventInSandbox({
  839. id: refId,
  840. value: "321",
  841. name: "Keystroke",
  842. willCommit: true
  843. });
  844. expect(send_queue.has(refId)).toEqual(true);
  845. expect(send_queue.get(refId)).toEqual({
  846. id: refId,
  847. value: "321",
  848. valueAsString: "321"
  849. });
  850. });
  851. it("should invalidate a number out of range [a, b]", async () => {
  852. const refId = getId();
  853. const data = {
  854. objects: {
  855. field: [{
  856. id: refId,
  857. value: "",
  858. actions: {
  859. Validate: [`AFRange_Validate(true, 123, true, 456);`]
  860. },
  861. type: "text"
  862. }]
  863. },
  864. appInfo: {
  865. language: "en-US",
  866. platform: "Linux x86_64"
  867. },
  868. calculationOrder: [],
  869. dispatchEventName: "_dispatchMe"
  870. };
  871. sandbox.createSandbox(data);
  872. await sandbox.dispatchEventInSandbox({
  873. id: refId,
  874. value: "12",
  875. name: "Keystroke",
  876. willCommit: true
  877. });
  878. expect(send_queue.has("alert")).toEqual(true);
  879. expect(send_queue.get("alert")).toEqual({
  880. command: "alert",
  881. value: "Invalid value: must be greater than or equal to 123 and less than or equal to 456."
  882. });
  883. });
  884. });
  885. describe("ASSimple_Calculate", function () {
  886. it("should compute the sum of several fields", async () => {
  887. const refIds = [0, 1, 2, 3].map(_ => getId());
  888. const data = {
  889. objects: {
  890. field1: [{
  891. id: refIds[0],
  892. value: "",
  893. actions: {},
  894. type: "text"
  895. }],
  896. field2: [{
  897. id: refIds[1],
  898. value: "",
  899. actions: {},
  900. type: "text"
  901. }],
  902. field3: [{
  903. id: refIds[2],
  904. value: "",
  905. actions: {},
  906. type: "text"
  907. }],
  908. field4: [{
  909. id: refIds[3],
  910. value: "",
  911. actions: {
  912. Calculate: [`AFSimple_Calculate("SUM", ["field1", "field2", "field3"]);`]
  913. },
  914. type: "text"
  915. }]
  916. },
  917. appInfo: {
  918. language: "en-US",
  919. platform: "Linux x86_64"
  920. },
  921. calculationOrder: [refIds[3]],
  922. dispatchEventName: "_dispatchMe"
  923. };
  924. sandbox.createSandbox(data);
  925. await sandbox.dispatchEventInSandbox({
  926. id: refIds[0],
  927. value: "1",
  928. name: "Keystroke",
  929. willCommit: true
  930. });
  931. expect(send_queue.has(refIds[3])).toEqual(true);
  932. expect(send_queue.get(refIds[3])).toEqual({
  933. id: refIds[3],
  934. value: 1,
  935. valueAsString: "1"
  936. });
  937. await sandbox.dispatchEventInSandbox({
  938. id: refIds[1],
  939. value: "2",
  940. name: "Keystroke",
  941. willCommit: true
  942. });
  943. expect(send_queue.has(refIds[3])).toEqual(true);
  944. expect(send_queue.get(refIds[3])).toEqual({
  945. id: refIds[3],
  946. value: 3,
  947. valueAsString: "3"
  948. });
  949. await sandbox.dispatchEventInSandbox({
  950. id: refIds[2],
  951. value: "3",
  952. name: "Keystroke",
  953. willCommit: true
  954. });
  955. expect(send_queue.has(refIds[3])).toEqual(true);
  956. expect(send_queue.get(refIds[3])).toEqual({
  957. id: refIds[3],
  958. value: 6,
  959. valueAsString: "6"
  960. });
  961. });
  962. });
  963. describe("AFSpecial_KeystrokeEx", function () {
  964. it("should validate a phone number on a keystroke event", async () => {
  965. const refId = getId();
  966. const data = {
  967. objects: {
  968. field: [{
  969. id: refId,
  970. value: "",
  971. actions: {
  972. Keystroke: [`AFSpecial_KeystrokeEx("9AXO");`]
  973. },
  974. type: "text"
  975. }]
  976. },
  977. appInfo: {
  978. language: "en-US",
  979. platform: "Linux x86_64"
  980. },
  981. calculationOrder: [],
  982. dispatchEventName: "_dispatchMe"
  983. };
  984. sandbox.createSandbox(data);
  985. await sandbox.dispatchEventInSandbox({
  986. id: refId,
  987. value: "",
  988. change: "3",
  989. name: "Keystroke",
  990. willCommit: false,
  991. selStart: 0,
  992. selEnd: 0
  993. });
  994. expect(send_queue.has(refId)).toEqual(false);
  995. await sandbox.dispatchEventInSandbox({
  996. id: refId,
  997. value: "3",
  998. change: "F",
  999. name: "Keystroke",
  1000. willCommit: false,
  1001. selStart: 1,
  1002. selEnd: 1
  1003. });
  1004. expect(send_queue.has(refId)).toEqual(false);
  1005. await sandbox.dispatchEventInSandbox({
  1006. id: refId,
  1007. value: "3F",
  1008. change: "?",
  1009. name: "Keystroke",
  1010. willCommit: false,
  1011. selStart: 2,
  1012. selEnd: 2
  1013. });
  1014. expect(send_queue.has(refId)).toEqual(false);
  1015. await sandbox.dispatchEventInSandbox({
  1016. id: refId,
  1017. value: "3F?",
  1018. change: "@",
  1019. name: "Keystroke",
  1020. willCommit: false,
  1021. selStart: 3,
  1022. selEnd: 3
  1023. });
  1024. expect(send_queue.has(refId)).toEqual(true);
  1025. expect(send_queue.get(refId)).toEqual({
  1026. id: refId,
  1027. value: "3F?",
  1028. selRange: [3, 3]
  1029. });
  1030. send_queue.delete(refId);
  1031. await sandbox.dispatchEventInSandbox({
  1032. id: refId,
  1033. value: "3F?",
  1034. change: "0",
  1035. name: "Keystroke",
  1036. willCommit: true,
  1037. selStart: 3,
  1038. selEnd: 3
  1039. });
  1040. expect(send_queue.has(refId)).toEqual(false);
  1041. });
  1042. });
  1043. describe("eMailValidate", function () {
  1044. it("should validate an e-mail address", async () => {
  1045. let value = await myeval(`eMailValidate(123)`);
  1046. expect(value).toEqual(false);
  1047. value = await myeval(`eMailValidate("foo@bar.com")`);
  1048. expect(value).toEqual(true);
  1049. value = await myeval(`eMailValidate("foo bar")`);
  1050. expect(value).toEqual(false);
  1051. });
  1052. });
  1053. });
  1054. });