3 +--------------------------------------------------------------------+
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
29 * Tests for linking to resource files
32 class CRM_Utils_JSTest
extends CiviUnitTestCase
{
37 public function translateExamples() {
45 'alert("Hello world")',
48 // basic function call
50 'alert(ts("Hello world"));',
55 'alert(ts("Hello world", {1: "whiz"}));',
60 'alert(clients("Hello world"));',
65 'alert(clients("Hello world", {1: "whiz"}));',
71 "public function whits() {\n" .
73 " mitts(\"wallaby\", function(zoo) {\n" .
74 " alert(zoo + ts(\"Hello\"))\n" .
82 'alert(ts("Hello world") + "-" + ts("Hello world"));',
85 // two strings, addition
87 'alert(ts("Hello world") + "-" + ts("How do you do?"));',
88 ['Hello world', 'How do you do?'],
90 // two strings, separate calls
92 'alert(ts("Hello world");\nalert(ts("How do you do?"));',
93 ['Hello world', 'How do you do?'],
96 'alert(ts(\'Single quoted\'));',
101 'alert(ts(message));',
104 // ts() within a string
106 'alert(ts("Does the ts(\'example\') notation work?"));',
107 ['Does the ts(\'example\') notation work?'],
113 * @param string $jsCode
114 * @param array $expectedStrings
115 * @dataProvider translateExamples
117 public function testParseStrings($jsCode, $expectedStrings) {
118 $actualStrings = CRM_Utils_JS
::parseStrings($jsCode);
119 sort($expectedStrings);
120 sort($actualStrings);
121 $this->assertEquals($expectedStrings, $actualStrings);
124 public function dedupeClosureExamples() {
125 // Each example string here is named for its body, eg the body of $a calls "a()".
126 $a = "(function (angular, $, _) {\na();\n})(angular, CRM.$, CRM._);";
127 $b = "(function(angular,$,_){\nb();\n})(angular,CRM.$,CRM._);";
128 $c = "(function( angular, $,_) {\nc();\n})(angular,CRM.$, CRM._);";
129 $d = "(function (angular, $, _, whiz) {\nd();\n})(angular, CRM.$, CRM._, CRM.whizbang);";
130 $m = "alert('i is the trickster (function( angular, $,_) {\nm();\n})(angular,CRM.$, CRM._);)'";
131 // Note: $d has a fundamentally different closure.
133 // Each example string here is a deduped combination of others,
134 // eg "$ab" is the deduping of $a+$b.
135 $ab = "(function (angular, $, _) {\na();\n\nb();\n})(angular,CRM.$,CRM._);";
136 $abc = "(function (angular, $, _) {\na();\n\nb();\n\nc();\n})(angular,CRM.$, CRM._);";
137 $cb = "(function( angular, $,_) {\nc();\n\nb();\n})(angular,CRM.$,CRM._);";
140 $cases[] = [[$a], "$a"];
141 $cases[] = [[$b], "$b"];
142 $cases[] = [[$c], "$c"];
143 $cases[] = [[$d], "$d"];
144 $cases[] = [[$m], "$m"];
145 $cases[] = [[$a, $b], "$ab"];
146 $cases[] = [[$a, $m, $b], "$a$m$b"];
147 $cases[] = [[$a, $d], "$a$d"];
148 $cases[] = [[$a, $d, $b], "$a$d$b"];
149 $cases[] = [[$a, $b, $c], "$abc"];
150 $cases[] = [[$a, $b, $d, $c, $b], "$ab$d$cb"];
155 * @param array $scripts
156 * @param string $expectedOutput
157 * @dataProvider dedupeClosureExamples
159 public function testDedupeClosure($scripts, $expectedOutput) {
160 $actualOutput = CRM_Utils_JS
::dedupeClosures(
162 ['angular', '$', '_'],
163 ['angular', 'CRM.$', 'CRM._']
165 $this->assertEquals($expectedOutput, implode("", $actualOutput));
168 public function stripCommentsExamples() {
171 "a();\n//# sourceMappingURL=../foo/bar/baz.js\nb();",
183 "/// foo\na();\n\t \t//bar\nb();\n// whiz",
187 "alert('//# sourceMappingURL=../foo/bar/baz.js');\n//zoop\na();",
188 "alert('//# sourceMappingURL=../foo/bar/baz.js');\n\na();",
194 * @param string $input
195 * @param string $expectedOutput
196 * @dataProvider stripCommentsExamples
198 public function testStripComments($input, $expectedOutput) {
199 $this->assertEquals($expectedOutput, CRM_Utils_JS
::stripComments($input));
202 public static function decodeExamples() {
204 ['{a: \'Apple\', \'b\': "Banana", c: [1, 2, 3]}', ['a' => 'Apple', 'b' => 'Banana', 'c' => [1, 2, 3]]],
217 '{a: "parse error no closing bracket"',
221 '{a: ["foo", \'bar\'], "b": {a: [\'foo\', "bar"], b: {\'a\': ["foo", "bar"], b: {}}}}',
222 ['a' => ['foo', 'bar'], 'b' => ['a' => ['foo', 'bar'], 'b' => ['a' => ['foo', 'bar'], 'b' => []]]],
225 ' [{a: {aa: true}, b: [false, null, {x: 1, y: 2, z: 3}] , "c": -1}, ["fee", "fie", \'foe\']]',
226 [['a' => ['aa' => TRUE], 'b' => [FALSE, NULL, ['x' => 1, 'y' => 2, 'z' => 3]], "c" => -1], ["fee", "fie", "foe"]],
232 * @param string $input
233 * @param string $expectedOutput
234 * @dataProvider decodeExamples
236 public function testDecode($input, $expectedOutput) {
237 $this->assertEquals($expectedOutput, CRM_Utils_JS
::decode($input));
240 public static function encodeExamples() {
243 ['a' => 'Apple', 'b' => 'Banana', 'c' => [0, -2, 3.15]],
244 "{a: 'Apple', b: 'Banana', c: [0, -2, 3.15]}",
247 ['a' => ['foo', 'bar'], 'b' => ["'a'" => ['foo/bar&', 'bar(foo)'], 'b' => ['a' => ["fo'oo", '"bar"'], 'b' => []]]],
248 "{a: ['foo', 'bar'], b: {\"'a'\": ['foo/bar&', 'bar(foo)'], b: {a: ['fo\\'oo', '\"bar\"'], b: {}}}}",
255 ['"false"', "'\"false\"'"],
263 * @param string $input
264 * @param string $expectedOutput
265 * @dataProvider encodeExamples
267 public function testEncode($input, $expectedOutput) {
268 $result = CRM_Utils_JS
::encode($input);
269 $this->assertEquals($expectedOutput, $result);
270 $this->assertEquals($input, CRM_Utils_JS
::decode($result));
276 public static function objectExamples() {
279 '{a: \'Apple\', \'b\': "Banana", "c ": [1,2,3]}',
280 ['a' => "'Apple'", 'b' => '"Banana"', 'c ' => '[1,2,3]'],
281 '{a: \'Apple\', b: "Banana", \'c \': [1,2,3]}',
294 " {'fn' : function (foo, bar, baz) { return \"One, two, three\"; }, esc: /[1-9]\\\\/.test('5\\\\') , number : 55.5/2 } ",
295 ['fn' => 'function (foo, bar, baz) { return "One, two, three"; }', 'esc' => "/[1-9]\\\\/.test('5\\\\')", 'number' => '55.5/2'],
296 "{fn: function (foo, bar, baz) { return \"One, two, three\"; }, esc: /[1-9]\\\\/.test('5\\\\'), number: 55.5/2}",
300 'this, has(some : weird, \\'stuff [{}!' ,
301 expr: sum(1, 2, 3) / 2 + 1, ' notes ' : [Do, re mi],
303 ['string' => "'this, has(some : weird, \\'stuff [{}!'", 'expr' => 'sum(1, 2, 3) / 2 + 1', ' notes ' => "[Do, re mi]"],
304 "{string: 'this, has(some : weird, \\'stuff [{}!', expr: sum(1, 2, 3) / 2 + 1, ' notes ': [Do, re mi]}",
307 '{status: /^http:\/\/civicrm\.com/.test(url) ? \'good\' : \'bad\' , \'foo\&\': getFoo("Some \"quoted\" thing"), "ba\'[(r": function() {return "bar"}}',
308 ['status' => '/^http:\/\/civicrm\.com/.test(url) ? \'good\' : \'bad\'', 'foo&' => 'getFoo("Some \"quoted\" thing")', "ba'[(r" => 'function() {return "bar"}'],
309 '{status: /^http:\/\/civicrm\.com/.test(url) ? \'good\' : \'bad\', "foo&": getFoo("Some \"quoted\" thing"), "ba\'[(r": function() {return "bar"}}',
312 '{"some\"key": typeof foo === \'number\' ? true : false , "O\'Really?": ",((,", \'A"quote"\': 1 + 1 , "\\\\\\&\\/" : 0}',
313 ['some"key' => 'typeof foo === \'number\' ? true : false', "O'Really?" => '",((,"', 'A"quote"' => '1 + 1', '\\&/' => '0'],
314 '{\'some"key\': typeof foo === \'number\' ? true : false, "O\'Really?": ",((,", \'A"quote"\': 1 + 1, "\\\\&/": 0}',
317 '[foo ? 1 : 2 , 3 , function() {return 1 + 1;}, /^http:\/\/civicrm\.com/.test(url) ? \'good\' : \'bad\' , 3.14 ]',
318 ['foo ? 1 : 2', '3', 'function() {return 1 + 1;}', '/^http:\/\/civicrm\.com/.test(url) ? \'good\' : \'bad\'', '3.14'],
319 '[foo ? 1 : 2, 3, function() {return 1 + 1;}, /^http:\/\/civicrm\.com/.test(url) ? \'good\' : \'bad\', 3.14]',
325 * Test converting a js string to a php array and back again.
327 * @param string $input
328 * @param string $expectedPHP
330 * @dataProvider objectExamples
332 public function testObjectToAndFromString($input, $expectedPHP, $expectedJS) {
333 $objectProps = CRM_Utils_JS
::getRawProps($input);
334 $this->assertEquals($expectedPHP, $objectProps);
335 $reformattedJS = CRM_Utils_JS
::writeObject($objectProps);
336 $this->assertEquals($expectedJS, $reformattedJS);
337 $this->assertEquals($expectedPHP, CRM_Utils_JS
::getRawProps($reformattedJS));