├── README.md └── es6-test.js /README.md: -------------------------------------------------------------------------------- 1 | # ES6 Test 2 | 3 | This is a small test suite that is meant to be run on websites as a bookmarklet to check their compatibility with the ECMAScript 6 Draft. 4 | 5 | The idea behind this is to prevent errors due to conflicting implementation between browsers and their incomplete polyfills by the websites. This can prevent bugs like [this](https://bugzilla.mozilla.org/show_bug.cgi?id=924386#c19), [this](https://bugzilla.mozilla.org/show_bug.cgi?id=883914) and [this](https://bugzilla.mozilla.org/show_bug.cgi?id=881782) from occuring. 6 | 7 | ## To Use 8 | 9 | Create a bookmarklet with the following JavaScript code: 10 | 11 | ```javascript 12 | javascript:(function () { 13 | var newScript = document.createElement('script'); 14 | newScript.type = 'text/javascript'; 15 | newScript.src = 'https://raw2.github.com/sankha93/es6-test/master/es6-test.js'; 16 | document.getElementsByTagName('body')[0].appendChild(newScript); 17 | })(); 18 | ``` 19 | 20 | Just click on the bookmarklet with the Webconsole open. You will see the results coming up! -------------------------------------------------------------------------------- /es6-test.js: -------------------------------------------------------------------------------- 1 | function assertEq(a, b, cx) { 2 | var leftChain, rightChain; 3 | function compare2Objects (x, y) { 4 | var p; 5 | if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') 6 | return true; 7 | 8 | if (x === y) 9 | return true; 10 | 11 | if ((typeof x === 'function' && typeof y === 'function') || 12 | (x instanceof Date && y instanceof Date) || 13 | (x instanceof RegExp && y instanceof RegExp) || 14 | (x instanceof String && y instanceof String) || 15 | (x instanceof Number && y instanceof Number)) { 16 | return x.toString() === y.toString(); 17 | } 18 | 19 | if (!(x instanceof Object && y instanceof Object)) 20 | return false; 21 | 22 | if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) 23 | return false; 24 | 25 | if (x.constructor !== y.constructor) 26 | return false; 27 | 28 | if (x.prototype !== y.prototype) 29 | return false; 30 | 31 | if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) 32 | return false; 33 | 34 | for (p in y) { 35 | if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) 36 | return false; 37 | else if (typeof y[p] !== typeof x[p]) 38 | return false; 39 | } 40 | 41 | for (p in x) { 42 | if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) 43 | return false; 44 | else if (typeof y[p] !== typeof x[p]) 45 | return false; 46 | 47 | switch (typeof (x[p])) { 48 | case 'object': 49 | case 'function': 50 | leftChain.push(x); 51 | rightChain.push(y); 52 | if (!compare2Objects (x[p], y[p])) 53 | return false; 54 | leftChain.pop(); 55 | rightChain.pop(); 56 | break; 57 | 58 | default: 59 | if (x[p] !== y[p]) 60 | return false; 61 | break; 62 | } 63 | } 64 | return true; 65 | } 66 | leftChain = []; 67 | rightChain = []; 68 | 69 | if (!compare2Objects(a, b)) 70 | throw Error("Assertion failed in " + cx + " : " + a + " === " + b); 71 | } 72 | 73 | function raiseImplError(obj) { 74 | throw new Error("Invalid implementation: " + obj); 75 | } 76 | 77 | function testMap() { 78 | try { 79 | var m = new Map([[1, 'a'], [2, 'b']]); 80 | m.size ? assertEq(m.size, 2, "Map.prototype.size") : raiseImplError("Map.prototype.size"); 81 | m.get ? assertEq(m.get(1), 'a', "Map.prototype.get()") : raiseImplError("Map.prototype.get()"); 82 | m.has ? assertEq(m.has(1), true, "Map.prototype.has()") : raiseImplError("Map.prototype.has()"); 83 | m.set ? m.set(3, 'c') : raiseImplError("Map.prototype.set()"); 84 | if (m.delete) { 85 | m.delete(2); 86 | assertEq(m.has(2), false, "Map.prototype.delete()"); 87 | } else 88 | raiseImplError("Map.prototype.delete()"); 89 | 90 | var it; 91 | if (m.entries) { 92 | it = m.entries(); 93 | assertEq(it.next(), {value: [1, 'a'], done: false}, "Map.prototype.entries()"); 94 | assertEq(it.next(), {value: [3, 'c'], done: false}, "Map.prototype.entries()"); 95 | assertEq(it.next(), {value: undefined, done: true}, "Map.prototype.entries()"); 96 | } else 97 | raiseImplError("Map.prototype.entries()"); 98 | 99 | if (m.keys) { 100 | it = m.keys(); 101 | assertEq(it.next(), {value: 1, done: false}, "Map.prototype.keys()"); 102 | assertEq(it.next(), {value: 3, done: false}, "Map.prototype.keys()"); 103 | assertEq(it.next(), {value: undefined, done: true}, "Map.prototype.keys()"); 104 | } else 105 | raiseImplError("Map.prototype.keys()"); 106 | 107 | if (m.values) { 108 | it = m.values(); 109 | assertEq(it.next(), {value: 'a', done: false}, "Map.prototype.values()"); 110 | assertEq(it.next(), {value: 'c', done: false}, "Map.prototype.values()"); 111 | assertEq(it.next(), {value: undefined, done: true}, "Map.prototype.values()"); 112 | } else 113 | raiseImplError("Map.prototype.values()"); 114 | 115 | if (m.clear) { 116 | m.clear(); 117 | assertEq(m.has(1), false, "Map.prototype.clear()"); 118 | } else 119 | raiseImplError("Map.prototype.clear()") 120 | } catch (e) { 121 | console.error(e.message); 122 | } 123 | } 124 | 125 | function testSet() { 126 | try { 127 | var s = new Set([1, 'a']); 128 | s.size ? assertEq(s.size, 2, "Set.prototype.size") : raiseImplError("Set.prototype.size"); 129 | s.has ? assertEq(s.has(1), true, "Set.prototype.has()") : raiseImplError("Set.prototype.has()"); 130 | s.add ? s.add(false) : raiseImplError("Set.prototype.add()"); 131 | if (s.delete) { 132 | s.delete('a'); 133 | assertEq(s.has('a'), false, "Set.prototype.delete()"); 134 | } else 135 | raiseImplError("Set.prototype.delete()"); 136 | 137 | var it; 138 | if (s.entries) { 139 | it = s.entries(); 140 | assertEq(it.next(), {value: [1, 1], done: false}, "Set.prototype.entries()"); 141 | assertEq(it.next(), {value: [false, false], done: false}, "Set.prototype.entries()"); 142 | assertEq(it.next(), {value: undefined, done: true}, "Set.prototype.entries()"); 143 | } else 144 | raiseImplError("Set.prototype.entries()"); 145 | 146 | if (s.keys) { 147 | it = s.keys(); 148 | assertEq(it.next(), {value: 1, done: false}, "Set.prototype.keys()"); 149 | assertEq(it.next(), {value: false, done: false}, "Set.prototype.keys()"); 150 | assertEq(it.next(), {value: undefined, done: true}, "Set.prototype.keys()"); 151 | } else 152 | raiseImplError("Set.prototype.keys()"); 153 | 154 | if (s.values) { 155 | it = s.values(); 156 | assertEq(it.next(), {value: 1, done: false}, "Set.prototype.values()"); 157 | assertEq(it.next(), {value: false, done: false}, "Set.prototype.values()"); 158 | assertEq(it.next(), {value: undefined, done: true}, "Set.prototype.values()"); 159 | } else 160 | raiseImplError("Set.prototype.values()"); 161 | 162 | if (s.clear) { 163 | s.clear(); 164 | assertEq(s.has(1), false, "Set.prototype.clear()"); 165 | } else 166 | raiseImplError("Set.prototype.clear()") 167 | } catch (e) { 168 | console.error(e.message); 169 | } 170 | } 171 | 172 | function testStringPrototypeContains() { 173 | try { 174 | assertEq("abc".contains("a"), true, methods[8][0]); 175 | assertEq("abc".contains("b"), true, methods[8][0]); 176 | assertEq("abc".contains("abc"), true, methods[8][0]); 177 | assertEq("abc".contains("bc"), true, methods[8][0]); 178 | assertEq("abc".contains("d"), false, methods[8][0]); 179 | assertEq("abc".contains("abcd"), false, methods[8][0]); 180 | assertEq("abc".contains("ac"), false, methods[8][0]); 181 | assertEq("abc".contains("abc", 0), true, methods[8][0]); 182 | assertEq("abc".contains("bc", 0), true, methods[8][0]); 183 | assertEq("abc".contains("de", 0), false, methods[8][0]); 184 | assertEq("abc".contains("bc", 1), true, methods[8][0]); 185 | assertEq("abc".contains("c", 1), true, methods[8][0]); 186 | assertEq("abc".contains("a", 1), false, methods[8][0]); 187 | assertEq("abc".contains("abc", 1), false, methods[8][0]); 188 | assertEq("abc".contains("c", 2), true, methods[8][0]); 189 | assertEq("abc".contains("d", 2), false, methods[8][0]); 190 | assertEq("abc".contains("dcd", 2), false, methods[8][0]); 191 | assertEq("abc".contains("a", 42), false, methods[8][0]); 192 | assertEq("abc".contains("a", Infinity), false, methods[8][0]); 193 | assertEq("abc".contains("ab", -43), true, methods[8][0]); 194 | assertEq("abc".contains("cd", -42), false, methods[8][0]); 195 | assertEq("abc".contains("ab", -Infinity), true, methods[8][0]); 196 | assertEq("abc".contains("cd", -Infinity), false, methods[8][0]); 197 | assertEq("abc".contains("ab", NaN), true, methods[8][0]); 198 | assertEq("abc".contains("cd", NaN), false, methods[8][0]); 199 | var myobj = {toString : function () {return "abc";}, contains : String.prototype.contains}; 200 | assertEq(myobj.contains("abc"), true, methods[8][0]); 201 | assertEq(myobj.contains("cd"), false, methods[8][0]); 202 | var gotStr = false, gotPos = false; 203 | myobj = {toString : (function () { 204 | assertEq(gotPos, false, methods[8][0]); 205 | gotStr = true; 206 | return "xyz"; 207 | }), 208 | contains : String.prototype.contains}; 209 | var idx = {valueOf : (function () { 210 | assertEq(gotStr, true, methods[8][0]); 211 | gotPos = true; 212 | return 42; 213 | })}; 214 | myobj.contains("elephant", idx, methods[8][0]); 215 | assertEq(gotPos, true, methods[8][0]); 216 | assertEq("xyzzy".contains("zy\0", 2), false, methods[8][0]); 217 | var dots = Array(10000).join('.'); 218 | assertEq(dots.contains("\x01", 10000), false, methods[8][0]); 219 | assertEq(dots.contains("\0", 10000), false, methods[8][0]); 220 | } catch (e) { 221 | console.error(e.message); 222 | } 223 | } 224 | 225 | function testArrayPrototypeEntries() { 226 | try { 227 | var arr = [1, 2]; 228 | var it = arr.entries(); 229 | assertEq(it.next(), {value: [0, 1], done: false}, methods[20][0]); 230 | assertEq(it.next(), {value: [1, 2], done: false}, methods[20][0]); 231 | arr.push('a'); 232 | assertEq(it.next(), {value: [2, 'a'], done: false}, methods[20][0]); 233 | assertEq(it.next(), {value: undefined, done: true}, methods[20][0]); 234 | } catch (e) { 235 | console.error(e.message); 236 | } 237 | } 238 | 239 | var methods = [["Map", testMap], 240 | ["Set", testSet], 241 | ["String.fromCodePoint",], 242 | ["String.raw",], 243 | ["String.prototype.codePointAt",], 244 | ["String.prototype.repeat",], 245 | ["String.prototype.startsWith",], 246 | ["String.prototype.endsWith",], 247 | ["String.prototype.contains", testStringPrototypeContains], 248 | ["Number.parseInt",], 249 | ["Number.parseFloat",], 250 | ["Number.isNaN",], 251 | ["Number.isSafeInteger",], 252 | ["Number.isFinite",], 253 | ["Number.prototype.clz",], 254 | ["Array.from",], 255 | ["Array.of",], 256 | ["Array.prototype.find",], 257 | ["Array.prototype.findIndex",], 258 | ["Array.prototype.keys",], 259 | ["Array.prototype.entries", testArrayPrototypeEntries], 260 | ["Array.prototype.values",], 261 | ["Object.is",], 262 | ["Object.assign",], 263 | ["Math.sign",], 264 | ["Math.log10",], 265 | ["Math.log2",], 266 | ["Math.log1p",], 267 | ["Math.expm1",], 268 | ["Math.cosh",], 269 | ["Math.sinh",], 270 | ["Math.tanh",], 271 | ["Math.acosh",], 272 | ["Math.asinh",], 273 | ["Math.atanh",], 274 | ["Math.hypot",], 275 | ["Math.trunc",], 276 | ["Math.imul",]]; 277 | 278 | var notExists = 0; 279 | var notExistsNames = []; 280 | var context = window; 281 | 282 | for (var i = 0; i < methods.length; i++) { 283 | var namespaces = methods[i][0].split("."); 284 | var func = namespaces.pop(); 285 | var tmpContext = context; 286 | for(var j = 0; j < namespaces.length; j++) { 287 | tmpContext = tmpContext[namespaces[j]]; 288 | } 289 | if (!tmpContext[func]) { 290 | notExists++; 291 | notExistsNames.push(methods[i][0]); 292 | } else if (methods[i][1]) 293 | methods[i][1](); 294 | } 295 | 296 | console.log(notExists + " out of " + methods.length + " methods are not supported."); 297 | console.log(notExistsNames); 298 | --------------------------------------------------------------------------------