IE 11 "Expected Identifier" error on spread operator found in AJV code - internet-explorer-11

In my Angular 6 app, I'm getting a console error in IE 11 as "Script1010: "Expected Identifier". No issues with evergreen browsers.
The error occurs at the first "." in the spread operator function, identified in the bundled js file is:
function(e,t,n){"use strict";function 1(...e){if(e.length>1)
{e[0]=e[0].slice(0,-1);const t=e.length-1;for(let n=1;n<t;++n)e[n]=e[n].slice(1,-1);return e[t]=e[t].slice(1),e.join("")}
Searching on keywords around this line of code, I've identified that it comes from the ajv.min.js file, specifically, perhaps within this code section from the file:
44: [function(e, r, t) {
var a;
a = this,
function(e) {
"use strict";
function C() {
for (var e = arguments.length, r = Array(e), t = 0; t < e; t++) r[t] = arguments[t];
if (1 < r.length) {
r[0] = r[0].slice(0, -1);
for (var a = r.length - 1, s = 1; s < a; ++s) r[s] = r[s].slice(1, -1);
return r[a] = r[a].slice(1), r.join("")
}
return r[0]
}
Apparently, the spread operator is not being transpiled into something IE11 can digest and the browser chokes on the first period in the (...e) function argument with an "Expected Identifier" error.
Any suggestions for workarounds or specific polyfills to fix the issue?

IE browser not support the Spread syntax and Rest parameter, to get the same result, you could refer to the following methods:
Method 1:
Using JavaScript methods (such as: foreach or array method) to loop through the parameter or array items, instead of using Spread syntax or Rest Parameter. More details information, please check the following links:
Spread Operator equivalent in IE - Javascript
ES6 spread syntax IE not supported
Alternatives of spread syntax
Method 2:
using #babel/polyfill and the babel-plugin-transform-object-rest-spread polyfills. Try to use the following command to install the polyfill:
npm install --save #babel/polyfill
npm install --save-dev babel-plugin-transform-object-rest-spread
Besides, since IE browser not support ES 6 syntax, please check your polyfills.ts file, and uncomment the related package for IE browser.
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
import 'core-js/es6/symbol';
import 'core-js/es6/object';
import 'core-js/es6/function';
import 'core-js/es6/parse-int';
import 'core-js/es6/parse-float';
import 'core-js/es6/number';
import 'core-js/es6/math';
import 'core-js/es6/string';
import 'core-js/es6/date';
import 'core-js/es6/array';
import 'core-js/es6/regexp';
import 'core-js/es6/map';
import 'core-js/es6/weak-map';
import 'core-js/es6/set';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/** IE10 and IE11 requires the following for the Reflect API. */
import 'core-js/es6/reflect';
/** Evergreen browsers require these. **/
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
import 'core-js/es7/reflect';

The issue here was with punycode.js. Forcing punycode.js to version 1.4.1 fixes the issue. Our version of ajv was causing a later version of punycode.js to load and that version contains ES6 code that trips up IE.

Related

SPFX 1.7.1 webpart is not working on IE11

I have created a new SharePoint web part (version 1.7.1). I'm using the react template. The web part is very basic, yet doesn't run on IE 11.
The error returned is
Object doesn't support property or method 'find'
I don't use find in any of my .ts files, so I found the .find method is being called by the .js files that were transpiled from my .ts files.
Can anybody confirm this to be a bug in SPFX v1.7.1?
If so, is there a solution.
I know this could be fixed by introducing a shim, but I don't know how to configure this for SPFX and can't find any documentation that explains how to do this.
Any help is welcome.
If I recall correctly, this is because IE 11 doesn't support Element.closest, which is used by the React engine.
I have personally used element-closest to polyfill it, although I'm sure other options exist.
// beginning of WebPart code file
import 'element-closest/browser';
import * as React from 'react';
import * as ReactDom from 'react-dom';
// rest of the code, etc.
With refer to this article, we can see that the Array.prototype.find() method not support IE browser. But, This method has been added to the ECMAScript 2015 specification and may not be available in all JavaScript implementations yet. However, you can polyfill Array.prototype.find with the following snippet:
// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
value: function(predicate) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1];
// 5. Let k be 0.
var k = 0;
// 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
// d. If testResult is true, return kValue.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
}
// e. Increase k by 1.
k++;
}
// 7. Return undefined.
return undefined;
},
configurable: true,
writable: true
});
}
Besides, as far as I know, when we use React, by default, the generated react project supports all modern browsers. Support for Internet Explorer 9, 10, and 11 requires polyfills. You could check it and import related packages.
You can adjust your tsconfig.json file: set "target" to "es5" under "compilerOptions".
Typescript will create polyfills for you.
I had the same issue. Use this import in your webpart.ts file.
import 'core-js/modules/es6.array.find';

elm init, make, install and stuff inside reactor fail with HTTP PROBLEM

I'm trying to run a simple counter example app (from here):
import Html exposing (button, div, text)
import Html.Events exposing (onClick)
main =
Html.beginnerProgram {
model = init,
update = update,
view = view
}
init =
{ count = 0 }
type Msg = Increment
view model =
div[] [
text model.count,
button [ onClick Increment ][ text "increment" ]
]
update = Increment model =
{ model | count = model.count + 1 }
My project folder looks like this:
package.json // created with npm init , npm install --save-dev elm
elm.json // since elm init fails, copy-pasted from https://github.com/elm/compiler/blob/master/docs/elm.json/application.md
src/Main.elm // the file shown above
node_modules/...
When I try to run elm init (before elm.json was created) or elm make src/Main.elm or elm install elm-lang/html, I get the following error (the socket number differs):
-- HTTP PROBLEM ----------------------------------------------------------------
The following HTTP request failed:
<https://package.elm-lang.org/all-packages>
Here is the error message I was able to extract:
HttpExceptionRequest Request { host = "package.elm-lang.org" port = 443
secure = True requestHeaders =
[("User-Agent","elm/0.19.0"),("Accept-Encoding","gzip")] path =
"/all-packages" queryString = "" method = "GET" proxy = Nothing rawBody =
False redirectCount = 10 responseTimeout = ResponseTimeoutDefault
requestVersion = HTTP/1.1 } (InternalException (HostCannotConnect
"package.elm-lang.org" [Network.Socket.connect: <socket: 728>: failed
(Connection timed out (WSAETIMEDOUT))]))
I also get the same thing when in elm reactor I try to open Main.elm (screenshot on the bottom just in case).
Is this a problem of the elm binary? I'm on Windows and installed elm 0.19; I've tried to disable my firewall just in case, but that didn't help.
Any ideas what can be the source of the problem? Googling gives rather irrelevant results... not sure what to do to fix this.

Selenium send keys incorrect order in Stripe credit card input

After sending keys to an input field with selenium, the result is not as expected - the keys are inserted in incorrect order.
e.g. send_keys('4242424242424242') -> result is "4224242424242424"
EDIT: On some machines I observe the issue only randomly, 1 case out of 10 attempts. On another machine it is 10/10
This happens specifically with Stripe payment form + I see this problem only in Chrome version 69 (in previous versions it worked OK)
This can be easily reproduced on sample Stripe site: https://stripe.github.io/elements-examples/
Sample python code:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://stripe.github.io/elements-examples/')
driver.switch_to.frame(driver.find_element_by_tag_name('iframe')) # First iframe
cc_input = driver.find_element_by_css_selector('input[name="cardnumber"]')
cc_input.send_keys('4242424242424242')
Result:
I am able to get pass this by sending the keys one by one with slight delay - but this is also not 100% reliable (plus terribly slow)
I am not sure if this is a problem with selenium (3.14.1)/chromedriver (2.41.578737) or if I am doing something wrong.
Any ideas please?
We are having the exact same problem on MacOS and Ubuntu 18.04, as well as on our CI server with protractor 5.4.1 and the same version of selenium and chromedriver. It has only started failing since Chrome 69, worse in v70.
Update - Working (for the moment)
After much further investigation, I remembered that React tends to override change/input events, and that the values in the credit card input, ccv input etc are being rendered from the React Component State, not from just the input value. So I started looking, and found What is the best way to trigger onchange event in react js
Our tests are working (for the moment):
//Example credit input
function creditCardInput (): ElementFinder {
return element(by.xpath('//input[contains(#name, "cardnumber")]'))
}
/// ... snippet of our method ...
await ensureCreditCardInputIsReady()
await stripeInput(creditCardInput, ccNumber)
await stripeInput(creditCardExpiry, ccExpiry)
await stripeInput(creditCardCvc, ccCvc)
await browser.wait(this.hasCreditCardZip(), undefined, 'Should have a credit card zip')
await stripeInput(creditCardZip, ccZip)
await browser.switchTo().defaultContent()
/// ... snip ...
async function ensureCreditCardInputIsReady (): Promise<void> {
await browser.wait(ExpectedConditions.presenceOf(paymentIFrame()), undefined, 'Should have a payment iframe')
await browser.switchTo().frame(await paymentIFrame().getWebElement())
await browser.wait(
ExpectedConditions.presenceOf(creditCardInput()),
undefined,
'Should have a credit card input'
)
}
/**
* SendKeys for the Stripe gateway was having issues in Chrome since version 69. Keys were coming in out of order,
* which resulted in failed tests.
*/
async function stripeInput (inputElement: Function, value: string): Promise<void> {
await browser.executeScript(`
var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
nativeInputValueSetter.call(arguments[0], '${value}');
var inputEvent = new Event('input', { bubbles: true});
arguments[0].dispatchEvent(inputEvent);
`, inputElement()
)
await browser.sleep(100)
const typedInValue = await inputElement().getWebElement().getAttribute('value')
if (typedInValue.replace(/\s/g, '') === value) {
return
}
throw new Error(`Failed set '${typedInValue}' on ${inputElement}`)
}
Previous Idea (only worked occasionally):
I have setup a minimal repro using https://stripe.com/docs/stripe-js/elements/quickstart and it succeeds when tests are run sequentially, but not in parallel (we think due to focus/blur issues when switching to the iframes).
Our solution is similar, although we noticed from watching the tests that input.clear() wasn't work on tel inputs which are used in the iframe.
This still fails occasionally, but far less frequently.
/**
* Types a value into an input field, and checks if the value of the input
* matches the expected value. If not, it attempts for `maxAttempts` times to
* type the value into the input again.
*
* This works around an issue with ChromeDriver where sendKeys() can send keys out of order,
* so a string like "0260" gets typed as "0206" for example.
*
* It also works around an issue with IEDriver where sendKeys() can press the SHIFT key too soon
* and cause letters or numbers to be converted to their SHIFT variants, "6" gets typed as "^", for example.
*/
export async function slowlyTypeOutField (
value: string,
inputElement: Function,
maxAttempts = 20
): Promise<void> {
for (let attemptNumber = 0; attemptNumber < maxAttempts; attemptNumber++) {
if (attemptNumber > 0) {
await browser.sleep(100)
}
/*
Executing a script seems to be a lot more reliable in setting these flaky fields than using the sendKeys built-in
method. However, I struggled in finding out which JavaScript events Stripe listens to. So we send the last key to
the input field to trigger all events we need.
*/
const firstPart = value.substring(0, value.length - 1)
const secondPart = value.substring(value.length - 1, value.length)
await browser.executeScript(`
arguments[0].focus();
arguments[0].value = "${firstPart}";
`,
inputElement()
)
await inputElement().sendKeys(secondPart)
const typedInValue = await inputElement().getAttribute('value')
if (typedInValue === value) {
return
}
console.log(`Tried to set value ${value}, but instead set ${typedInValue} on ${inputElement}`)
}
throw new Error(`Failed after ${maxAttempts} attempts to set value on ${inputElement}`)
}
I faced a similar issue in ubuntu 14.04, the following trick helped me.
Have not got any issue since.
First I used the regular send_keys method.
Then I called the execute script to update the value
input_data = "someimputdata"
some_xpath = "//*[contains(#id,'input_fax.number_')]"
element = web_driver_obj.find_element_by_xpath(some_xpath)
element.clear()
element.send_keys(input_data)
web_driver_obj.execute_script("arguments[0].value = '{0}';".format(input_data), element)
Edit
Thanks a lot to #Benno - his answer was correct.
I will just add python solution that worked for me, based on his JS
driver.get('https://stripe.github.io/elements-examples/')
driver.switch_to.frame(driver.find_element_by_tag_name('iframe')) # First iframe
cc_input = driver.find_element_by_css_selector('input[name="cardnumber"]')
value = "4242424242424242"
driver.execute_script('''
input = arguments[0];
var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
nativeInputValueSetter.call(input, "{}");
var eventCard = new Event("input", {{bubbles: true}});
input.dispatchEvent(eventCard);
'''.format(value), cc_input)
driver.switch_to.default_content()
driver.quit()
After couple of hours of trying, I gave up and accepted the fact that this is really a random issue and went with a workaround.
Where it is not necessary to update, I will stay with Chrome version < 69
In order to test latest Chrome, I will use React solution
What I've found out
The issue manifested itself mostly on MacOS, quite rarely on Windows (there are most probably other factors in play, this is just an observation)
I've run an experiment with 100 repetitions of filling the form.
Mac - 68 failures
Windows - 6 failures
The cookies/local history (as suggested in comments) do not seem to be the problem. The webdriver always spawned a "clean" instance of the browser, with no cookies or local storage.
Maybe my solution will help for somebody:
I used sendKeys(" 4242424242424242")
Same for cvc field
With a space before string, it actually works for selenide + chrome + java
You could make your own generic SendKeys method that takes the input element and the string you would like to send. The method would split the string into individual characters and then use the selenium sendkeys method on each character.
Adding in some backspaces worked for me for whatever reason:
from selenium.webdriver.common.keys import Keys
my_value = "123"
my_xpath="//input[#class='form-text']"
element = driver.find_element_by_xpath(my_xpath)
element.clear()
element.send_keys(Keys.BACKSPACE * 3, my_value)
I was having the same issue using RSelenium and got the idea to try adding spaces to the credit card number as they appear on the card from #Pavel's answer, since adding a space before the card number didn't work for me.
Using RSelenium this would be:
element$sendKeysToElement(list("4242 4242 4242 4242"))

Dynamic es6 module import names [duplicate]

Is it possible to import something into a module providing a variable name while using ES6 import?
I.e. I want to import some module at a runtime depending on values provided in a config:
import something from './utils/' + variableName;
Note that I’m using Node.js, but answers must take compatibility with ECMAScript modules into consideration.
Not with the import statement. import and export are defined in such a way that they are statically analyzable, so they cannot depend on runtime information.
You are looking for the loader API (polyfill), but I'm a bit unclear about the status of the specification:
System.import('./utils/' + variableName).then(function(m) {
console.log(m);
});
Whilst this is not actually a dynamic import (eg in my circumstance, all the files I'm importing below will be imported and bundled by webpack, not selected at runtime), a pattern I've been using which may assist in some circumstances is:
import Template1 from './Template1.js';
import Template2 from './Template2.js';
const templates = {
Template1,
Template2
};
export function getTemplate (name) {
return templates[name];
}
or alternatively:
// index.js
export { default as Template1 } from './Template1';
export { default as Template2 } from './Template2';
// OtherComponent.js
import * as templates from './index.js'
...
// handy to be able to fall back to a default!
return templates[name] || templates.Template1;
I don't think I can fall back to a default as easily with require(), which throws an error if I try to import a constructed template path that doesn't exist.
Good examples and comparisons between require and import can be found here: http://www.2ality.com/2014/09/es6-modules-final.html
Excellent documentation on re-exporting from #iainastacio:
http://exploringjs.com/es6/ch_modules.html#sec_all-exporting-styles
I'm interested to hear feedback on this approach :)
There is a new specification which is called a dynamic import for ES modules.
Basically, you just call import('./path/file.js') and you're good to go. The function returns a promise, which resolves with the module if the import was successful.
async function importModule() {
try {
const module = await import('./path/module.js');
} catch (error) {
console.error('import failed');
}
}
Use cases
Use-cases include route based component importing for React, Vue etc and the ability to lazy load modules, once they are required during runtime.
Further Information
Here's is an explanation on Google Developers.
Browser compatibility (April 2020)
According to MDN it is supported by every current major browser (except IE) and caniuse.com shows 87% support across the global market share. Again no support in IE or non-chromium Edge.
In addition to Felix's answer, I'll note explicitly that this is not currently allowed by the ECMAScript 6 grammar:
ImportDeclaration :
import ImportClause FromClause ;
import ModuleSpecifier ;
FromClause :
from ModuleSpecifier
ModuleSpecifier :
StringLiteral
A ModuleSpecifier can only be a StringLiteral, not any other kind of expression like an AdditiveExpression.
I understand the question specifically asked for ES6 import in Node.js, but the following might help others looking for a more generic solution:
let variableName = "es5.js";
const something = require(`./utils/${variableName}`);
Note if you're importing an ES6 module and need to access the default export, you will need to use one of the following:
let variableName = "es6.js";
// Assigning
const defaultMethod = require(`./utils/${variableName}`).default;
// Accessing
const something = require(`./utils/${variableName}`);
something.default();
You can also use destructuring with this approach which may add more syntax familiarity with your other imports:
// Destructuring
const { someMethod } = require(`./utils/${variableName}`);
someMethod();
Unfortunately, if you want to access default as well as destructuring, you will need to perform this in multiple steps:
// ES6 Syntax
Import defaultMethod, { someMethod } from "const-path.js";
// Destructuring + default assignment
const something = require(`./utils/${variableName}`);
const defaultMethod = something.default;
const { someMethod, someOtherMethod } = something;
you can use the non-ES6 notation to do that. this is what worked for me:
let myModule = null;
if (needsToLoadModule) {
myModule = require('my-module').default;
}
I had similar problem using Vue.js: When you use variable in import(variableName) at build time Webpack doesn't know where to looking for. So you have to restrict it to known path with propriate extension like that:
let something = import("#/" + variableName + ".js")
That answer in github for the same issue was very helpful for me.
I less like this syntax, but it work:
instead of writing
import memberName from "path" + "fileName";
// this will not work!, since "path" + "fileName" need to be string literal
use this syntax:
let memberName = require("path" + "fileName");
Dynamic import() (available in Chrome 63+) will do your job. Here's how:
let variableName = 'test.js';
let utilsPath = './utils/' + variableName;
import(utilsPath).then((module) => { module.something(); });
./utils/test.js
export default () => {
doSomething...
}
call from file
const variableName = 'test';
const package = require(`./utils/${variableName}`);
package.default();
I would do it like this
function load(filePath) {
return () => System.import(`${filePath}.js`);
// Note: Change .js to your file extension
}
let A = load('./utils/' + variableName)
// Now you can use A in your module
It depends. You can use template literals in dynamic imports to import a file based on a variable.
I used dynamic imports to add .vue files to vue router. I have excluded the Home.vue view import.
const pages = [
'About',
['About', 'Team'],
]
const nodes = [
{
name: 'Home',
path: '/',
component: Home,
}
]
for (const page of pages) {
if (typeof page === 'string') {
nodes.push({
name: page,
path: `/${page}`,
component: import(`./views/${page}.vue`),
})
} else {
nodes.push({
name: _.last(page),
path: `/${page.join('/')}`,
component: import(`./views/${_.last(page)}.vue`)
})
}
}
This worked for me. I was using yarn + vite + vue on replit.

Exception Error: chrome://app/content/app1.js - EXPORTED_SYMBOLS is not an array

"EXPORTED_SYMBOLS is not an array" Exception flagged when tried to use Components.utils.import("chrome://app/content/app1.js");.
I have a XUL application created and from one of the JS File(say app.js) I tried to include the other JS File as shown above.
Both app.js and app1.js are placed in content folder and also in chrome.manifest file following line is added
"content app content/"
In other JS File (app1.js), I have exported symbols like
var EXPORTED_SYMBOLS = ["Fooinstance"];
var Fooinstance = {
foo: function() {
...
}
}
In app.js,
Components.utils.import("chrome://app/content/app1.js");
// Error: chrome://app/content/app1.js - EXPORTED_SYMBOLS is not an array
...
Fooinstance.foo();
I am running this XUL app on XULRunner 17.0.1 win32 libraries.
I looked through the code in this link https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Using
It did not help and if I include it as resource it works however I do not want to include it as part of resource.
Could you someone point out what mistake would be ?
I had this same problem, and I solved it:
1) changing the file extension (.js) by .jsm
2) Adding a first line on your module exporting classes to share. EG:
var EXPORTED_SYMBOLS = ["Xobject"];
function Xobject(){
}
Xobject.prototype.stop = function() {
return 'stop';
}
Xobject.prototype.run = function() {
return 'running';
}
3) Calling this way
Components.utils.import('resource://gre/modules/Services.jsm' );
Components.utils.import("chrome://myFirstAddOn/content/Xobject.jsm");
var myXobject = new Xobject();
alert(myXobject.run());
Hope it help u
For anyone else getting this, another possible reason is a circular dependency. My case was a little different, but I had two JSM files each using Components.utils.import to import each other. Then I got this error in one of them.