UNPKG

5.64 kBJavaScriptView Raw
1'use strict';
2
3/* globals Proxy */
4/* eslint no-magic-numbers: 1 */
5
6var test = require('tape');
7var isCallable = require('../');
8var hasToStringTag = require('has-tostringtag/shams')();
9var v = require('es-value-fixtures');
10var forEach = require('for-each');
11var inspect = require('object-inspect');
12var typedArrayNames = require('available-typed-arrays')();
13var generators = require('make-generator-function')();
14var arrows = require('make-arrow-function').list();
15var asyncs = require('make-async-function').list();
16var weirdlyCommentedArrowFn;
17try {
18 /* eslint-disable no-new-func */
19 weirdlyCommentedArrowFn = Function('return cl/*/**/=>/**/ass - 1;')();
20 /* eslint-enable no-new-func */
21} catch (e) { /**/ }
22
23var noop = function () {};
24var classFake = function classFake() { }; // eslint-disable-line func-name-matching
25var returnClass = function () { return ' class '; };
26var return3 = function () { return 3; };
27/* for coverage */
28noop();
29classFake();
30returnClass();
31return3();
32/* end for coverage */
33
34var proxy;
35if (typeof Proxy === 'function') {
36 try {
37 proxy = new Proxy(function () {}, {});
38 // for coverage
39 proxy();
40 String(proxy);
41 } catch (_) {
42 // If `Reflect` is supported, then `Function.prototype.toString` isn't used for callability detection.
43 if (typeof Reflect !== 'object') {
44 // Older engines throw a `TypeError` when `Function.prototype.toString` is called on a Proxy object.
45 proxy = null;
46 }
47 }
48}
49
50var invokeFunction = function invokeFunctionString(str) {
51 var result;
52 try {
53 /* eslint-disable no-new-func */
54 var fn = Function(str);
55 /* eslint-enable no-new-func */
56 result = fn();
57 } catch (e) {}
58 return result;
59};
60
61var classConstructor = invokeFunction('"use strict"; return class Foo {}');
62
63var commentedClass = invokeFunction('"use strict"; return class/*kkk*/\n//blah\n Bar\n//blah\n {}');
64var commentedClassOneLine = invokeFunction('"use strict"; return class/**/A{}');
65var classAnonymous = invokeFunction('"use strict"; return class{}');
66var classAnonymousCommentedOneLine = invokeFunction('"use strict"; return class/*/*/{}');
67
68test('not callables', function (t) {
69 t.notOk(isCallable(), 'implicit undefined is not callable');
70
71 forEach(v.nonFunctions.concat([
72 Object(42),
73 Object('foo'),
74 NaN,
75 [],
76 /a/g,
77 new RegExp('a', 'g'),
78 new Date()
79 ]), function (nonFunction) {
80 t.equal(isCallable(nonFunction), false, inspect(nonFunction) + ' is not callable');
81 });
82
83 t.test('non-function with function in its [[Prototype]] chain', function (st) {
84 var Foo = function Bar() {};
85 Foo.prototype = noop;
86 st.equal(isCallable(Foo), true, 'sanity check: Foo is callable');
87 st.equal(isCallable(new Foo()), false, 'instance of Foo is not callable');
88 st.end();
89 });
90
91 t.end();
92});
93
94test('@@toStringTag', { skip: !hasToStringTag }, function (t) {
95 var fakeFunction = {
96 toString: function () { return String(return3); },
97 valueOf: return3
98 };
99 fakeFunction[Symbol.toStringTag] = 'Function';
100 t.equal(String(fakeFunction), String(return3));
101 t.equal(Number(fakeFunction), return3());
102 t.notOk(isCallable(fakeFunction), 'fake Function with @@toStringTag "Function" is not callable');
103 t.end();
104});
105
106test('Functions', function (t) {
107 t.ok(isCallable(noop), 'function is callable');
108 t.ok(isCallable(classFake), 'function with name containing "class" is callable');
109 t.ok(isCallable(returnClass), 'function with string " class " is callable');
110 t.ok(isCallable(isCallable), 'isCallable is callable');
111 t.end();
112});
113
114test('Typed Arrays', { skip: typedArrayNames.length === 0 }, function (st) {
115 forEach(typedArrayNames, function (typedArray) {
116 st.ok(isCallable(global[typedArray]), typedArray + ' is callable');
117 });
118 st.end();
119});
120
121test('Generators', { skip: generators.length === 0 }, function (t) {
122 forEach(generators, function (genFn) {
123 t.ok(isCallable(genFn), 'generator function ' + genFn + ' is callable');
124 });
125 t.end();
126});
127
128test('Arrow functions', { skip: arrows.length === 0 }, function (t) {
129 forEach(arrows, function (arrowFn) {
130 t.ok(isCallable(arrowFn), 'arrow function ' + arrowFn + ' is callable');
131 });
132 t.ok(isCallable(weirdlyCommentedArrowFn), 'weirdly commented arrow functions are callable');
133 t.end();
134});
135
136test('"Class" constructors', { skip: !classConstructor || !commentedClass || !commentedClassOneLine || !classAnonymous }, function (t) {
137 t.notOk(isCallable(classConstructor), 'class constructors are not callable');
138 t.notOk(isCallable(commentedClass), 'class constructors with comments in the signature are not callable');
139 t.notOk(isCallable(commentedClassOneLine), 'one-line class constructors with comments in the signature are not callable');
140 t.notOk(isCallable(classAnonymous), 'anonymous class constructors are not callable');
141 t.notOk(isCallable(classAnonymousCommentedOneLine), 'anonymous one-line class constructors with comments in the signature are not callable');
142 t.end();
143});
144
145test('`async function`s', { skip: asyncs.length === 0 }, function (t) {
146 forEach(asyncs, function (asyncFn) {
147 t.ok(isCallable(asyncFn), '`async function` ' + asyncFn + ' is callable');
148 });
149 t.end();
150});
151
152test('proxies of functions', { skip: !proxy }, function (t) {
153 t.ok(isCallable(proxy), 'proxies of functions are callable');
154 t.end();
155});
156
157test('throwing functions', function (t) {
158 t.plan(1);
159
160 var thrower = function (a) { return a.b; };
161 t.ok(isCallable(thrower), 'a function that throws is callable');
162});
163
164/* globals document: false */
165test('document.all', { skip: typeof document !== 'object' }, function (t) {
166 t.notOk(isCallable(document), 'document is not callable');
167 t.ok(isCallable(document.all), 'document.all is callable');
168
169 t.end();
170});