scripting_spec.js 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365
  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([4, 5, 6, 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().replace(/T.*$/, "")`);
  540. expect(value).toEqual(new Date(expected).toISOString().replace(/T.*$/, ""));
  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. await check("a1$9bbbb21", "dd/mm/yyyy", "2021/09/01");
  546. });
  547. });
  548. describe("AFExtractNums", function () {
  549. it("should extract numbers", async () => {
  550. let value = await myeval(`AFExtractNums("123 456 789")`);
  551. expect(value).toEqual(["123", "456", "789"]);
  552. value = await myeval(`AFExtractNums("123.456")`);
  553. expect(value).toEqual(["123", "456"]);
  554. value = await myeval(`AFExtractNums("123")`);
  555. expect(value).toEqual(["123"]);
  556. value = await myeval(`AFExtractNums(".123")`);
  557. expect(value).toEqual(["0", "123"]);
  558. value = await myeval(`AFExtractNums(",123")`);
  559. expect(value).toEqual(["0", "123"]);
  560. });
  561. });
  562. describe("AFMakeNumber", function () {
  563. it("should convert string to number", async () => {
  564. let value = await myeval(`AFMakeNumber("123.456")`);
  565. expect(value).toEqual(123.456);
  566. value = await myeval(`AFMakeNumber(123.456)`);
  567. expect(value).toEqual(123.456);
  568. value = await myeval(`AFMakeNumber("-123.456")`);
  569. expect(value).toEqual(-123.456);
  570. value = await myeval(`AFMakeNumber("-123,456")`);
  571. expect(value).toEqual(-123.456);
  572. value = await myeval(`AFMakeNumber("not a number")`);
  573. expect(value).toEqual(null);
  574. });
  575. });
  576. describe("AFMakeArrayFromList", function () {
  577. it("should split a string into an array of strings", async () => {
  578. const value = await myeval(`AFMakeArrayFromList("aaaa, bbbbbbb,cc,ddd, e")`);
  579. expect(value).toEqual(["aaaa", " bbbbbbb", "cc", "ddd", "e"]);
  580. });
  581. });
  582. describe("AFNumber_format", function () {
  583. it("should format a number", async () => {
  584. const refId = getId();
  585. const data = {
  586. objects: {
  587. field: [{
  588. id: refId,
  589. value: "",
  590. actions: {
  591. test1: [`AFNumber_Format(2, 0, 0, 0, "€", false);` + `event.source.value = event.value;`],
  592. test2: [`AFNumber_Format(1, 3, 0, 0, "$", true);` + `event.source.value = event.value;`],
  593. test3: [`AFNumber_Format(2, 0, 1, 0, "€", false);` + `event.source.value = event.value;`],
  594. test4: [`AFNumber_Format(2, 0, 2, 0, "€", false);` + `event.source.value = event.value;`],
  595. test5: [`AFNumber_Format(2, 0, 3, 0, "€", false);` + `event.source.value = event.value;`]
  596. },
  597. type: "text"
  598. }]
  599. },
  600. appInfo: {
  601. language: "en-US",
  602. platform: "Linux x86_64"
  603. },
  604. calculationOrder: [],
  605. dispatchEventName: "_dispatchMe"
  606. };
  607. sandbox.createSandbox(data);
  608. await sandbox.dispatchEventInSandbox({
  609. id: refId,
  610. value: "123456.789",
  611. name: "test1"
  612. });
  613. expect(send_queue.has(refId)).toEqual(true);
  614. expect(send_queue.get(refId)).toEqual({
  615. id: refId,
  616. value: "123,456.79€"
  617. });
  618. send_queue.delete(refId);
  619. await sandbox.dispatchEventInSandbox({
  620. id: refId,
  621. value: "223456.789",
  622. name: "test2"
  623. });
  624. expect(send_queue.has(refId)).toEqual(true);
  625. expect(send_queue.get(refId)).toEqual({
  626. id: refId,
  627. value: "$223456,8"
  628. });
  629. send_queue.delete(refId);
  630. await sandbox.dispatchEventInSandbox({
  631. id: refId,
  632. value: "-323456.789",
  633. name: "test3"
  634. });
  635. expect(send_queue.has(refId)).toEqual(true);
  636. expect(send_queue.get(refId)).toEqual({
  637. id: refId,
  638. value: "323,456.79€",
  639. textColor: ["RGB", 1, 0, 0]
  640. });
  641. send_queue.delete(refId);
  642. await sandbox.dispatchEventInSandbox({
  643. id: refId,
  644. value: "-423456.789",
  645. name: "test4"
  646. });
  647. expect(send_queue.has(refId)).toEqual(true);
  648. expect(send_queue.get(refId)).toEqual({
  649. id: refId,
  650. value: "(423,456.79€)"
  651. });
  652. send_queue.delete(refId);
  653. await sandbox.dispatchEventInSandbox({
  654. id: refId,
  655. value: "-52345.678",
  656. name: "test5"
  657. });
  658. expect(send_queue.has(refId)).toEqual(true);
  659. expect(send_queue.get(refId)).toEqual({
  660. id: refId,
  661. value: "(52,345.68€)",
  662. textColor: ["RGB", 1, 0, 0]
  663. });
  664. });
  665. });
  666. describe("AFNumber_Keystroke", function () {
  667. it("should validate a number on a keystroke event", async () => {
  668. const refId = getId();
  669. const data = {
  670. objects: {
  671. field: [{
  672. id: refId,
  673. value: "",
  674. actions: {
  675. Validate: [`AFNumber_Keystroke(null, 0, null, null, null, null);`]
  676. },
  677. type: "text",
  678. name: "MyField"
  679. }]
  680. },
  681. appInfo: {
  682. language: "en-US",
  683. platform: "Linux x86_64"
  684. },
  685. calculationOrder: [],
  686. dispatchEventName: "_dispatchMe"
  687. };
  688. sandbox.createSandbox(data);
  689. await sandbox.dispatchEventInSandbox({
  690. id: refId,
  691. value: "123456.789",
  692. name: "Keystroke",
  693. willCommit: true
  694. });
  695. expect(send_queue.has(refId)).toEqual(true);
  696. expect(send_queue.get(refId)).toEqual({
  697. id: refId,
  698. siblings: null,
  699. value: "123456.789",
  700. formattedValue: null
  701. });
  702. });
  703. it("should not validate a number on a keystroke event", async () => {
  704. const refId = getId();
  705. const data = {
  706. objects: {
  707. field: [{
  708. id: refId,
  709. value: "",
  710. actions: {
  711. Validate: [`AFNumber_Keystroke(null, 0, null, null, null, null);`]
  712. },
  713. type: "text",
  714. name: "MyField"
  715. }]
  716. },
  717. appInfo: {
  718. language: "en-US",
  719. platform: "Linux x86_64"
  720. },
  721. calculationOrder: [],
  722. dispatchEventName: "_dispatchMe"
  723. };
  724. sandbox.createSandbox(data);
  725. await sandbox.dispatchEventInSandbox({
  726. id: refId,
  727. value: "123s456.789",
  728. name: "Keystroke",
  729. willCommit: true
  730. });
  731. expect(send_queue.has("alert")).toEqual(true);
  732. expect(send_queue.get("alert")).toEqual({
  733. command: "alert",
  734. value: "The value entered does not match the format of the field [ MyField ]"
  735. });
  736. });
  737. });
  738. describe("AFPercent_Format", function () {
  739. it("should format a percentage", async () => {
  740. const refId = getId();
  741. const data = {
  742. objects: {
  743. field: [{
  744. id: refId,
  745. value: "",
  746. actions: {
  747. test1: [`AFPercent_Format(2, 1, false);` + `event.source.value = event.value;`],
  748. test2: [`AFPercent_Format(2, 1, true);` + `event.source.value = event.value;`]
  749. },
  750. type: "text"
  751. }]
  752. },
  753. appInfo: {
  754. language: "en-US",
  755. platform: "Linux x86_64"
  756. },
  757. calculationOrder: [],
  758. dispatchEventName: "_dispatchMe"
  759. };
  760. sandbox.createSandbox(data);
  761. await sandbox.dispatchEventInSandbox({
  762. id: refId,
  763. value: "0.456789",
  764. name: "test1"
  765. });
  766. expect(send_queue.has(refId)).toEqual(true);
  767. expect(send_queue.get(refId)).toEqual({
  768. id: refId,
  769. value: "45.68%"
  770. });
  771. send_queue.delete(refId);
  772. await sandbox.dispatchEventInSandbox({
  773. id: refId,
  774. value: "0.456789",
  775. name: "test2"
  776. });
  777. expect(send_queue.has(refId)).toEqual(true);
  778. expect(send_queue.get(refId)).toEqual({
  779. id: refId,
  780. value: "%45.68"
  781. });
  782. });
  783. });
  784. describe("AFDate_Format", function () {
  785. it("should format a date", async () => {
  786. const refId = getId();
  787. const data = {
  788. objects: {
  789. field: [{
  790. id: refId,
  791. value: "",
  792. actions: {
  793. test1: [`AFDate_Format(0);event.source.value = event.value;`],
  794. test2: [`AFDate_Format(12);event.source.value = event.value;`]
  795. },
  796. type: "text"
  797. }]
  798. },
  799. appInfo: {
  800. language: "en-US",
  801. platform: "Linux x86_64"
  802. },
  803. calculationOrder: [],
  804. dispatchEventName: "_dispatchMe"
  805. };
  806. sandbox.createSandbox(data);
  807. await sandbox.dispatchEventInSandbox({
  808. id: refId,
  809. value: "Sun Apr 15 2007 03:14:15",
  810. name: "test1"
  811. });
  812. expect(send_queue.has(refId)).toEqual(true);
  813. expect(send_queue.get(refId)).toEqual({
  814. id: refId,
  815. value: "4/15"
  816. });
  817. send_queue.delete(refId);
  818. await sandbox.dispatchEventInSandbox({
  819. id: refId,
  820. value: "Sun Apr 15 2007 03:14:15",
  821. name: "test2"
  822. });
  823. expect(send_queue.has(refId)).toEqual(true);
  824. expect(send_queue.get(refId)).toEqual({
  825. id: refId,
  826. value: "4/15/07 3:14 am"
  827. });
  828. });
  829. });
  830. describe("AFRange_Validate", function () {
  831. it("should validate a number in range [a, b]", async () => {
  832. const refId = getId();
  833. const data = {
  834. objects: {
  835. field: [{
  836. id: refId,
  837. value: "",
  838. actions: {
  839. Validate: [`AFRange_Validate(true, 123, true, 456);`]
  840. },
  841. type: "text"
  842. }]
  843. },
  844. appInfo: {
  845. language: "en-US",
  846. platform: "Linux x86_64"
  847. },
  848. calculationOrder: [],
  849. dispatchEventName: "_dispatchMe"
  850. };
  851. sandbox.createSandbox(data);
  852. await sandbox.dispatchEventInSandbox({
  853. id: refId,
  854. value: "321",
  855. name: "Keystroke",
  856. willCommit: true
  857. });
  858. expect(send_queue.has(refId)).toEqual(true);
  859. expect(send_queue.get(refId)).toEqual({
  860. id: refId,
  861. siblings: null,
  862. value: "321",
  863. formattedValue: null
  864. });
  865. });
  866. it("should invalidate a number out of range [a, b]", async () => {
  867. const refId = getId();
  868. const data = {
  869. objects: {
  870. field: [{
  871. id: refId,
  872. value: "",
  873. actions: {
  874. Validate: [`AFRange_Validate(true, 123, true, 456);`]
  875. },
  876. type: "text"
  877. }]
  878. },
  879. appInfo: {
  880. language: "en-US",
  881. platform: "Linux x86_64"
  882. },
  883. calculationOrder: [],
  884. dispatchEventName: "_dispatchMe"
  885. };
  886. sandbox.createSandbox(data);
  887. await sandbox.dispatchEventInSandbox({
  888. id: refId,
  889. value: "12",
  890. name: "Keystroke",
  891. willCommit: true
  892. });
  893. expect(send_queue.has("alert")).toEqual(true);
  894. expect(send_queue.get("alert")).toEqual({
  895. command: "alert",
  896. value: "Invalid value: must be greater than or equal to 123 and less than or equal to 456."
  897. });
  898. });
  899. });
  900. describe("AFSimple_Calculate", function () {
  901. it("should compute the sum of several fields", async () => {
  902. const refIds = [0, 1, 2, 3, 4].map(_ => getId());
  903. const data = {
  904. objects: {
  905. field1: [{
  906. id: refIds[0],
  907. value: "",
  908. actions: {},
  909. type: "text"
  910. }],
  911. field2: [{
  912. id: refIds[1],
  913. value: "",
  914. actions: {},
  915. type: "text"
  916. }],
  917. field3: [{
  918. id: refIds[2],
  919. value: "",
  920. actions: {},
  921. type: "text"
  922. }],
  923. field4: [{
  924. id: refIds[3],
  925. value: "",
  926. actions: {
  927. Calculate: [`AFSimple_Calculate("SUM", ["field1", "field2", "field3", "unknown"]);`]
  928. },
  929. type: "text"
  930. }],
  931. field5: [{
  932. id: refIds[4],
  933. value: "",
  934. actions: {
  935. Calculate: [`AFSimple_Calculate("SUM", "field1, field2, field3, unknown");`]
  936. },
  937. type: "text"
  938. }]
  939. },
  940. appInfo: {
  941. language: "en-US",
  942. platform: "Linux x86_64"
  943. },
  944. calculationOrder: [refIds[3], refIds[4]],
  945. dispatchEventName: "_dispatchMe"
  946. };
  947. sandbox.createSandbox(data);
  948. await sandbox.dispatchEventInSandbox({
  949. id: refIds[0],
  950. value: "1",
  951. name: "Keystroke",
  952. willCommit: true
  953. });
  954. expect(send_queue.has(refIds[3])).toEqual(true);
  955. expect(send_queue.get(refIds[3])).toEqual({
  956. id: refIds[3],
  957. siblings: null,
  958. value: 1,
  959. formattedValue: null
  960. });
  961. await sandbox.dispatchEventInSandbox({
  962. id: refIds[1],
  963. value: "2",
  964. name: "Keystroke",
  965. willCommit: true
  966. });
  967. expect(send_queue.has(refIds[3])).toEqual(true);
  968. expect(send_queue.get(refIds[3])).toEqual({
  969. id: refIds[3],
  970. siblings: null,
  971. value: 3,
  972. formattedValue: null
  973. });
  974. await sandbox.dispatchEventInSandbox({
  975. id: refIds[2],
  976. value: "3",
  977. name: "Keystroke",
  978. willCommit: true
  979. });
  980. expect(send_queue.has(refIds[3])).toEqual(true);
  981. expect(send_queue.get(refIds[3])).toEqual({
  982. id: refIds[3],
  983. siblings: null,
  984. value: 6,
  985. formattedValue: null
  986. });
  987. expect(send_queue.has(refIds[4])).toEqual(true);
  988. expect(send_queue.get(refIds[4])).toEqual({
  989. id: refIds[4],
  990. siblings: null,
  991. value: 6,
  992. formattedValue: null
  993. });
  994. });
  995. it("should compute the sum of several fields in fields tree", async () => {
  996. const refIds = [0, 1, 2, 3, 4, 5].map(_ => getId());
  997. const data = {
  998. objects: {
  999. field1: [{
  1000. id: refIds[0],
  1001. kidIds: [refIds[1], refIds[2]]
  1002. }],
  1003. "field1.field2": [{
  1004. id: refIds[1],
  1005. kidIds: [refIds[3]]
  1006. }],
  1007. "field1.field3": [{
  1008. id: refIds[2],
  1009. value: "",
  1010. actions: {},
  1011. type: "text"
  1012. }],
  1013. "field1.field2.field4": [{
  1014. id: refIds[3],
  1015. kidIds: [refIds[4]]
  1016. }],
  1017. "field1.field2.field4.field5": [{
  1018. id: refIds[4],
  1019. value: "",
  1020. actions: {},
  1021. type: "text"
  1022. }],
  1023. field6: [{
  1024. id: refIds[5],
  1025. value: "",
  1026. actions: {
  1027. Calculate: [`AFSimple_Calculate("SUM", "field1");`]
  1028. },
  1029. type: "text"
  1030. }]
  1031. },
  1032. appInfo: {
  1033. language: "en-US",
  1034. platform: "Linux x86_64"
  1035. },
  1036. calculationOrder: [refIds[5]],
  1037. dispatchEventName: "_dispatchMe"
  1038. };
  1039. sandbox.createSandbox(data);
  1040. await sandbox.dispatchEventInSandbox({
  1041. id: refIds[2],
  1042. value: "123",
  1043. name: "Keystroke",
  1044. willCommit: true
  1045. });
  1046. expect(send_queue.has(refIds[5])).toEqual(true);
  1047. expect(send_queue.get(refIds[5])).toEqual({
  1048. id: refIds[5],
  1049. siblings: null,
  1050. value: 123,
  1051. formattedValue: null
  1052. });
  1053. await sandbox.dispatchEventInSandbox({
  1054. id: refIds[4],
  1055. value: "456",
  1056. name: "Keystroke",
  1057. willCommit: true
  1058. });
  1059. expect(send_queue.has(refIds[5])).toEqual(true);
  1060. expect(send_queue.get(refIds[5])).toEqual({
  1061. id: refIds[5],
  1062. siblings: null,
  1063. value: 579,
  1064. formattedValue: null
  1065. });
  1066. });
  1067. });
  1068. describe("AFSpecial_KeystrokeEx", function () {
  1069. it("should validate a phone number on a keystroke event", async () => {
  1070. const refId = getId();
  1071. const data = {
  1072. objects: {
  1073. field: [{
  1074. id: refId,
  1075. value: "",
  1076. actions: {
  1077. Keystroke: [`AFSpecial_KeystrokeEx("9AXO");`]
  1078. },
  1079. type: "text"
  1080. }]
  1081. },
  1082. appInfo: {
  1083. language: "en-US",
  1084. platform: "Linux x86_64"
  1085. },
  1086. calculationOrder: [],
  1087. dispatchEventName: "_dispatchMe"
  1088. };
  1089. sandbox.createSandbox(data);
  1090. await sandbox.dispatchEventInSandbox({
  1091. id: refId,
  1092. value: "",
  1093. change: "3",
  1094. name: "Keystroke",
  1095. willCommit: false,
  1096. selStart: 0,
  1097. selEnd: 0
  1098. });
  1099. expect(send_queue.has(refId)).toEqual(true);
  1100. send_queue.delete(refId);
  1101. await sandbox.dispatchEventInSandbox({
  1102. id: refId,
  1103. value: "3",
  1104. change: "F",
  1105. name: "Keystroke",
  1106. willCommit: false,
  1107. selStart: 1,
  1108. selEnd: 1
  1109. });
  1110. expect(send_queue.has(refId)).toEqual(true);
  1111. send_queue.delete(refId);
  1112. await sandbox.dispatchEventInSandbox({
  1113. id: refId,
  1114. value: "3F",
  1115. change: "?",
  1116. name: "Keystroke",
  1117. willCommit: false,
  1118. selStart: 2,
  1119. selEnd: 2
  1120. });
  1121. expect(send_queue.has(refId)).toEqual(true);
  1122. send_queue.delete(refId);
  1123. await sandbox.dispatchEventInSandbox({
  1124. id: refId,
  1125. value: "3F?",
  1126. change: "@",
  1127. name: "Keystroke",
  1128. willCommit: false,
  1129. selStart: 3,
  1130. selEnd: 3
  1131. });
  1132. expect(send_queue.has(refId)).toEqual(true);
  1133. expect(send_queue.get(refId)).toEqual({
  1134. id: refId,
  1135. siblings: null,
  1136. value: "3F?",
  1137. selRange: [3, 3]
  1138. });
  1139. send_queue.delete(refId);
  1140. await sandbox.dispatchEventInSandbox({
  1141. id: refId,
  1142. value: "3F?",
  1143. change: "0",
  1144. name: "Keystroke",
  1145. willCommit: false,
  1146. selStart: 3,
  1147. selEnd: 3
  1148. });
  1149. expect(send_queue.has(refId)).toEqual(true);
  1150. send_queue.delete(refId);
  1151. await sandbox.dispatchEventInSandbox({
  1152. id: refId,
  1153. value: "3F?0",
  1154. name: "Keystroke",
  1155. willCommit: true,
  1156. selStart: 4,
  1157. selEnd: 4
  1158. });
  1159. expect(send_queue.has(refId)).toEqual(true);
  1160. expect(send_queue.get(refId)).toEqual({
  1161. id: refId,
  1162. siblings: null,
  1163. value: "3F?0",
  1164. formattedValue: null
  1165. });
  1166. });
  1167. });
  1168. describe("AFSpecial_Keystroke", function () {
  1169. it("should validate a zip code on a keystroke event", async () => {
  1170. const refId = getId();
  1171. const data = {
  1172. objects: {
  1173. field: [{
  1174. id: refId,
  1175. value: "",
  1176. actions: {
  1177. Keystroke: [`AFSpecial_Keystroke(0);`]
  1178. },
  1179. type: "text"
  1180. }]
  1181. },
  1182. appInfo: {
  1183. language: "en-US",
  1184. platform: "Linux x86_64"
  1185. },
  1186. calculationOrder: [],
  1187. dispatchEventName: "_dispatchMe"
  1188. };
  1189. sandbox.createSandbox(data);
  1190. let value = "";
  1191. const changes = "12345";
  1192. let i = 0;
  1193. for (; i < changes.length; i++) {
  1194. const change = changes.charAt(i);
  1195. await sandbox.dispatchEventInSandbox({
  1196. id: refId,
  1197. value,
  1198. change,
  1199. name: "Keystroke",
  1200. willCommit: false,
  1201. selStart: i,
  1202. selEnd: i
  1203. });
  1204. expect(send_queue.has(refId)).toEqual(true);
  1205. send_queue.delete(refId);
  1206. value += change;
  1207. }
  1208. await sandbox.dispatchEventInSandbox({
  1209. id: refId,
  1210. value,
  1211. change: "A",
  1212. name: "Keystroke",
  1213. willCommit: false,
  1214. selStart: i,
  1215. selEnd: i
  1216. });
  1217. expect(send_queue.has(refId)).toEqual(true);
  1218. expect(send_queue.get(refId)).toEqual({
  1219. id: refId,
  1220. siblings: null,
  1221. value,
  1222. selRange: [i, i]
  1223. });
  1224. send_queue.delete(refId);
  1225. });
  1226. it("should validate a US phone number (long) on a keystroke event", async () => {
  1227. const refId = getId();
  1228. const data = {
  1229. objects: {
  1230. field: [{
  1231. id: refId,
  1232. value: "",
  1233. actions: {
  1234. Keystroke: [`AFSpecial_Keystroke(2);`]
  1235. },
  1236. type: "text"
  1237. }]
  1238. },
  1239. appInfo: {
  1240. language: "en-US",
  1241. platform: "Linux x86_64"
  1242. },
  1243. calculationOrder: [],
  1244. dispatchEventName: "_dispatchMe"
  1245. };
  1246. sandbox.createSandbox(data);
  1247. let value = "";
  1248. const changes = "(123) 456-7890";
  1249. let i = 0;
  1250. for (; i < changes.length; i++) {
  1251. const change = changes.charAt(i);
  1252. await sandbox.dispatchEventInSandbox({
  1253. id: refId,
  1254. value,
  1255. change,
  1256. name: "Keystroke",
  1257. willCommit: false,
  1258. selStart: i,
  1259. selEnd: i
  1260. });
  1261. expect(send_queue.has(refId)).toEqual(true);
  1262. send_queue.delete(refId);
  1263. value += change;
  1264. }
  1265. await sandbox.dispatchEventInSandbox({
  1266. id: refId,
  1267. value,
  1268. change: "A",
  1269. name: "Keystroke",
  1270. willCommit: false,
  1271. selStart: i,
  1272. selEnd: i
  1273. });
  1274. expect(send_queue.has(refId)).toEqual(true);
  1275. expect(send_queue.get(refId)).toEqual({
  1276. id: refId,
  1277. siblings: null,
  1278. value,
  1279. selRange: [i, i]
  1280. });
  1281. send_queue.delete(refId);
  1282. });
  1283. it("should validate a US phone number (short) on a keystroke event", async () => {
  1284. const refId = getId();
  1285. const data = {
  1286. objects: {
  1287. field: [{
  1288. id: refId,
  1289. value: "",
  1290. actions: {
  1291. Keystroke: [`AFSpecial_Keystroke(2);`]
  1292. },
  1293. type: "text"
  1294. }]
  1295. },
  1296. appInfo: {
  1297. language: "en-US",
  1298. platform: "Linux x86_64"
  1299. },
  1300. calculationOrder: [],
  1301. dispatchEventName: "_dispatchMe"
  1302. };
  1303. sandbox.createSandbox(data);
  1304. let value = "";
  1305. const changes = "123-4567";
  1306. let i = 0;
  1307. for (; i < changes.length; i++) {
  1308. const change = changes.charAt(i);
  1309. await sandbox.dispatchEventInSandbox({
  1310. id: refId,
  1311. value,
  1312. change,
  1313. name: "Keystroke",
  1314. willCommit: false,
  1315. selStart: i,
  1316. selEnd: i
  1317. });
  1318. expect(send_queue.has(refId)).toEqual(true);
  1319. send_queue.delete(refId);
  1320. value += change;
  1321. }
  1322. await sandbox.dispatchEventInSandbox({
  1323. id: refId,
  1324. value,
  1325. change: "A",
  1326. name: "Keystroke",
  1327. willCommit: false,
  1328. selStart: i,
  1329. selEnd: i
  1330. });
  1331. expect(send_queue.has(refId)).toEqual(true);
  1332. expect(send_queue.get(refId)).toEqual({
  1333. id: refId,
  1334. siblings: null,
  1335. value,
  1336. selRange: [i, i]
  1337. });
  1338. send_queue.delete(refId);
  1339. });
  1340. });
  1341. describe("eMailValidate", function () {
  1342. it("should validate an e-mail address", async () => {
  1343. let value = await myeval(`eMailValidate(123)`);
  1344. expect(value).toEqual(false);
  1345. value = await myeval(`eMailValidate("foo@bar.com")`);
  1346. expect(value).toEqual(true);
  1347. value = await myeval(`eMailValidate("foo bar")`);
  1348. expect(value).toEqual(false);
  1349. });
  1350. });
  1351. describe("AFExactMatch", function () {
  1352. it("should check matching between regexs and a string", async () => {
  1353. let value = await myeval(`AFExactMatch(/\\d+/, "123")`);
  1354. expect(value).toEqual(true);
  1355. value = await myeval(`AFExactMatch(/\\d+/, "foo")`);
  1356. expect(value).toEqual(0);
  1357. value = await myeval(`AFExactMatch([/\\d+/, /[fo]*/], "foo")`);
  1358. expect(value).toEqual(2);
  1359. value = await myeval(`AFExactMatch([/\\d+/, /[fo]*/], "bar")`);
  1360. expect(value).toEqual(0);
  1361. });
  1362. });
  1363. });
  1364. });