Use data from session storage web in Polymer - javascript

I have a website made with Polymer that when you log in, it returns you in the session storage a key userData with values docID, name, surname and surname2, and then it enters to the platform. Those values are stored in the session storage of the browser.
I want to use those values except the docID and bring it to my code for plot it in the log in view/page, but I don't know how to use the session storage to take those parameters.
I made a fake user but with local storage that works with last time of connection but I don't know how to use it with session and receiving data from a website. This is my script:
Polymer({
date: null,
timeDate: null,
keyStorage: 'lastConnection',
ready: function(){
this.storageDate();
this.timeDate = this.getLastDateConnection();
this.storageUser();
this.fakeUserName = this.getUser();
},
getLastDateConnection: function(){
var date = new Date(parseInt(localStorage.getItem(this.keyStorage)));
return [date.getHours(),('0'+date.getMinutes()).slice(-2)].join(':');
},
storageDate: function(){
localStorage.setItem(this.keyStorage, +new Date);
},
getUser: function(){
var name = [localStorage.getItem("firstname") + " " + localStorage.getItem("lastname")];
return name;
},
storageUser:function(){
localStorage.setItem("lastname", "Vader");
localStorage.setItem("firstname", "Dark");
}
});
I want to do something similar except I have to storage the user data with session storage and from a website (I don't know the info until someone gets logged), so I suppose that I shouldn't do a setItem and just made a getItem receiving the key "userData" from the website. Any help/idea? Thanks!
PS: Maybe should I store the user info in my local storage after I receive the userData from the session storage if I want to keep the username? What I want to do is something equal to what Google do with our gmail accounts (you logg-in and when you want to enter again, it stores your account).

Ok, so I think I got it.
in the ready function is to make the call of the function that storages the session storage with:
ready: function(){
this.setData();
this.myUser = this.storageUser();
},
setData: function() {
sessionStorage.setItem("userData",userData);
},
and then storage the session storage in the local making a parse of the object:
storageUser: function(){
var userData = sessionStorage.getItem("userData");
var myObject = JSON.parse(userData);
var userName = [myObject.name + " " + myObject.surname];
return userName;
},
This is working on principle.

I know this is an old post but for new people who land on this page, this session storage element might be of help. It's behaviour is exactly like local storage.
<!--
#license
Copyright (c) 2015 The PlatinumIndustries.pl. All rights reserved.
This code may only be used under the BSD style license.
-->
<link rel="import" href="../polymer/polymer.html">
<!--
Element access to Web Storage API (window.sessionStorage).
Keeps `value` property in sync with sessionStorage.
Value is saved as json by default.
### Usage:
`Ss-sample` will automatically save changes to its value.
<dom-module id="ls-sample">
<iron-sessionstorage name="my-app-storage"
value="{{cartoon}}"
on-iron-sessionstorage-load-empty="initializeDefaultCartoon"
></iron-sessionstorage>
</dom-module>
<script>
Polymer({
is: 'ls-sample',
properties: {
cartoon: {
type: Object
}
},
// initializes default if nothing has been stored
initializeDefaultCartoon: function() {
this.cartoon = {
name: "Mickey",
hasEars: true
}
},
// use path set api to propagate changes to sessionstorage
makeModifications: function() {
this.set('cartoon.name', "Minions");
this.set('cartoon.hasEars', false);
}
});
</script>
### Tech notes:
* * `value.*` is observed, and saved on modifications. You must use
path change notifification methods such as `set()` to modify value
for changes to be observed.
* * Set `auto-save-disabled` to prevent automatic saving.
* * Value is saved as JSON by default.
* * To delete a key, set value to null
* Element listens to StorageAPI `storage` event, and will reload upon receiving it.
* **Warning**: do not bind value to sub-properties until Polymer
[bug 1550](https://github.com/Polymer/polymer/issues/1550)
is resolved. session storage will be blown away.
`<iron-sessionstorage value="{{foo.bar}}"` will cause **data loss**.
#demo demo/index.html
#hero hero.svg
-->
<dom-module id="iron-sessionstorage"></dom-module>
<script>
Polymer({
is: 'iron-sessionstorage',
properties: {
/**
* SessionStorage item key
*/
name: {
type: String,
value: ''
},
/**
* The data associated with this storage.
* If set to null item will be deleted.
* #type {*}
*/
value: {
type: Object,
notify: true
},
/**
* If true: do not convert value to JSON on save/load
*/
useRaw: {
type: Boolean,
value: false
},
/**
* Value will not be saved automatically if true. You'll have to do it manually with `save()`
*/
autoSaveDisabled: {
type: Boolean,
value: false
},
/**
* Last error encountered while saving/loading items
*/
errorMessage: {
type: String,
notify: true
},
/** True if value has been loaded */
_loaded: {
type: Boolean,
value: false
}
},
observers: [
'_debounceReload(name,useRaw)',
'_trySaveValue(autoSaveDisabled)',
'_trySaveValue(value.*)'
],
ready: function() {
this._boundHandleStorage = this._handleStorage.bind(this);
},
attached: function() {
window.addEventListener('storage', this._boundHandleStorage);
},
detached: function() {
window.removeEventListener('storage', this._boundHandleStorage);
},
_handleStorage: function(ev) {
if (ev.key == this.name) {
this._load(true);
}
},
_trySaveValue: function() {
if (this._doNotSave) {
return;
}
if (this._loaded && !this.autoSaveDisabled) {
this.debounce('save', this.save);
}
},
_debounceReload: function() {
this.debounce('reload', this.reload);
},
/**
* Loads the value again. Use if you modify
* sessionStorage using DOM calls, and want to
* keep this element in sync.
*/
reload: function() {
this._loaded = false;
this._load();
},
/**
* loads value from session storage
* #param {boolean=} externalChange true if loading changes from a different window
*/
_load: function(externalChange) {
var v = window.sessionStorage.getItem(this.name);
if (v === null) {
this._loaded = true;
this._doNotSave = true; // guard for save watchers
this.value = null;
this._doNotSave = false;
this.fire('iron-sessionstorage-load-empty', { externalChange: externalChange});
} else {
if (!this.useRaw) {
try { // parse value as JSON
v = JSON.parse(v);
} catch(x) {
this.errorMessage = "Could not parse session storage value";
console.error("could not parse sessionstorage value", v);
v = null;
}
}
this._loaded = true;
this._doNotSave = true;
this.value = v;
this._doNotSave = false;
this.fire('iron-sessionstorage-load', { externalChange: externalChange});
}
},
/**
* Saves the value to localStorage. Call to save if autoSaveDisabled is set.
* If `value` is null or undefined, deletes localStorage.
*/
save: function() {
var v = this.useRaw ? this.value : JSON.stringify(this.value);
try {
if (this.value === null || this.value === undefined) {
window.sessionStorage.removeItem(this.name);
} else {
window.sessionStorage.setItem(this.name, /** #type {string} */ (v));
}
}
catch(ex) {
// Happens in Safari incognito mode,
this.errorMessage = ex.message;
console.error("sessionStorage could not be saved. Safari incoginito mode?", ex);
}
}
/**
* Fired when value loads from localStorage.
*
* #event iron-localstorage-load
* #param {{externalChange:boolean}} detail -
* externalChange: true if change occured in different window.
*/
/**
* Fired when loaded value does not exist.
* Event handler can be used to initialize default value.
*
* #event iron-localstorage-load-empty
* #param {{externalChange:boolean}} detail -
* externalChange: true if change occured in different window.
*/
});
</script>

Related

No published solution seems to fix "Uncaught Error: Extension context invalidated. " Chrome extension manifest v3 [duplicate]

This question already has answers here:
Chrome extension content script re-injection after upgrade or install
(6 answers)
Chrome extension: How to remove orphaned script after chrom extension update
(2 answers)
Closed 4 months ago.
I've been building my first Chrome extension. It has been fun however I've run into a problem I've yet to solve.
I get the error in the devtools extentions Developer mode:
Uncaught Error: Extension context invalidated.
I pretty sure that upon update of my extension and hard refresh on my test https:// page that the contentScript.js gets injected multiple times. The older injected scripts are still trying to the dom injections but the ports are not open so it throws the error?
I have tried the solutions in both of these threads as well going through google groups:
Recursive "Extension context invalidated" error in console
Extension context invalidated. Chrome Extension
I am using manifest v3.
Can you please suggest a way that I can update my code to protect against this error?
Here is my manifest:
{
"name": "Focuser",
"description": "Focuses on a page during a specified time frame",
"version": "0.1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"permissions": [
"storage",
"scripting",
"alarms"
],
"host_permissions": [
"<all_urls>"
]
}
My background script:
try {
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if ('undefined' !== typeof tab.url) {
// skip urls like "chrome://" to avoid extension error
if (tab.url?.startsWith("chrome://")) return undefined;
if(changeInfo.status == 'complete') {
chrome.scripting.executeScript({
files: ['contentScript.js'],
target: {tabId: tab.id}
})
}
}
})
} catch(e) {
console.log(e)
}
My conentScript (with classes removed)
/**
* Foozle Focuser - a class that injects a temporary DOM element
* into the site and then focus and click on it.
*
* The idea is that by maintaining the focus while running in the background a
* Chrome tab can stream radio stations and other media content. This could be used
* for anything a user wants to click.
*/
class FoozleFocuser {
/**
* private {string} target
* the dom element used as the target for the inject DOM
*/
#target = null;
/**
* private {string} injectElement
* the DOM element used as the target for the injected DOM
*/
#injectElement = '';
/**
* private {string} injectElementClassName
* the CSS class to be added to the injected DOM element
*/
#injectElementClassName = '';
/**
* Constructor - set the target and injectElementClass - optionally no params passed
* will set a target as document.body and the injectClassName will be foozle-focuser
* #param {string} target - the passed target DOM element that will be used as the target for the injected DOM
* #param {string} injectElementClassName - the CSS class to be added to the injected DOM element
* #return Void
*/
constructor(target=null, injectElementClassName = 'foozle-focuser') {
this.#target = this.#getTarget(target);
this.#injectElementClassName = injectElementClassName;
}
/**
* private SetInjectedElement
* Creates the injected DOM element with a class that will be used as a target for the focus
* #param {string} domElement
* #return Void
*/
#setInjectedElement(domElement = 'div') {
this.#injectElement = document.createElement(domElement);
this.#injectElement.className = this.#injectElementClassName;
}
/**
* private getTarget - queries the passed dom string. If null set the document.body as target
* #param {string || null} target - The dom target element where the injection will be done
* #return string - the target
*/
#getTarget(target=null) {
if ( target == null ) {
target = document.body;
} else {
target = document.querySelector(target);
if ( target == null || 'undefined' == typeof target ) {
target = document.body;
}
}
return target;
}
/**
* private focus - appends, focuses on, and clicks the injected DOM Element
* #return Void
*/
#focus() {
if (this.#target) {
this.#target.appendChild(this.#injectElement);
this.#target.focus();
this.#target.click();
let newDiv = document.querySelector('.' + this.#injectElementClassName)
newDiv.parentNode.removeChild(newDiv);
}
}
/**
* private run - runs the setup for the target and injected element and then focuses on the target
* #return Void
*/
run() {
this.#setInjectedElement();
this.#focus();
}
}
class FoozleTypes {
typeOf(value) {
var s = typeof value;
if (s === 'object') {
if (value) {
if (Object.prototype.toString.call(value) == '[object Array]') {
s = 'array';
}
} else {
s = 'null';
}
}
return s;
}
checkTypes(argList, typeList) {
for (var i = 0; i < typeList.length; i++) {
if (typeOf(argList[i]) !== typeList[i]) {
throw 'wrong type: expecting ' + typeList[i] + ", found " + typeOf(argList[i]);
}
}
}
}
class FoozleCounter {
getStoredCount(key='focuserCount') {
this.item = localStorage.getItem(key);
if ( null == this.item || 'undefined' == this.item ) {
localStorage.setItem(key, 0);
}
this.item = parseInt(this.item)
let count = this.item;
count++;
localStorage.setItem(key, count);
return count;
}
}
let FC = new FoozleCounter();
let FF = new FoozleFocuser();
if ('undefined' == typeof intervalId) {
var intervalId = setInterval(() => {
if (!chrome.runtime?.id) {
// The extension was reloaded and this script is orphaned
clearInterval(intervalId);
return;
}
FF.run();
// Get the updated count
let count = FC.getStoredCount();
// Store and report the count
// #TODO - change the console log to the popup page
chrome.storage.local.set({key: count}, function() {
console.log('Count is set to ' + count);
});
}, 45000);
}
if('undefined' == typeof init ) {
var init = () => {
if (!chrome.runtime?.id) {
// The extension was reloaded and this script is orphaned
clearInterval(init);
return;
}
FF.run();
console.log('count', FC.getStoredCount())
}
init();
}
When the extension is auto-updated or reloaded on chrome://extensions page, its old content scripts are "orphaned" and can't use the chrome API anymore.
A universal solution is to re-inject the new content script in the above scenarios and send a DOM message to the orphaned content script so it can unregister its listeners and timers.
In your case, judging by the posted code, there's only setInterval, so the solution is simple:
var intervalId = setInterval(() => {
if (!chrome.runtime?.id) {
// The extension was reloaded and this script is orphaned
clearInterval(intervalId);
return;
}
//....................
//....................
//....................
}, 45000);
And of course you can re-inject the new content script if necessary.

AJAX request is cancelled by Chrome when issued from within the extension

I am doing a simple AJAX request within Chrome extension, but Chrome cancels my request each time. I did specify necessary cross-origin permissions in the manifest file. The server also allows cross-origin requests, i.e I am able to execute my ajax script within a normal browser window. I also tried doing the old way via XMLHttpRequest - the result is the same. What am I missing?
The full JS code loaded by extension is below (getUmsIdByEmail_ is the function):
var AssumeIdentityController = function () {
this.button_ = document.getElementById('button');
this.customer_email_ = document.getElementById('emailfield');
this.addListeners_();
};
AssumeIdentityController.prototype = {
/**
* A cached reference to the button element.
*
* #type {Element}
* #private
*/
button_: null,
/**
* A cached reference to the select element.
*
* #type {Element}
* #private
*/
timeframe_: null,
customer_email_: null,
/**
* Adds event listeners to the button in order to capture a user's click, and
* perform some action in response.
*
* #private
*/
addListeners_: function () {
this.button_.addEventListener('click', this.handleClick_.bind(this));
},
/**
* Given a string, return milliseconds since epoch. If the string isn't
* valid, returns undefined.
*
* #param {string} timeframe One of 'hour', 'day', 'week', '4weeks', or
* 'forever'.
* #returns {number} Milliseconds since epoch.
* #private
*/
getUmsIdByEmail_: function(email){
console.log('attempting to fetch');
var opts = {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
fetch('<SERVER_WITH_THE_RESOURCE>', opts).then(function (response) {
return response.json();
})
.then(function (body) {
console.log(body)
});
},
// getTokenByUms_: function(umsId) {
// return token
// }
/**
* Handle a success/failure callback from the `browsingData` API methods,
* updating the UI appropriately.
*
* #private
*/
handleCallback_: function () {
var success = document.createElement('div');
success.classList.add('overlay');
success.setAttribute('role', 'alert');
success.textContent = 'Data has been cleared.';
document.body.appendChild(success);
setTimeout(function() { success.classList.add('visible'); }, 10);
setTimeout(function() {
if (close === false)
success.classList.remove('visible');
else
window.close();
}, 4000);
},
/**
* When a user clicks the button, this method is called: it reads the current
* state of `timeframe_` in order to pull a timeframe, then calls the clearing
* method with appropriate arguments.
*
* #private
*/
handleClick_: function () {
this.getUmsIdByEmail_('sd');
if (this.customer_email_ !== undefined)
{
// var token = getTokenByUms(umsId);
// if(replacePreprodToken(token))
// {
// print('successfully logged in. Refreshing the page');
// }
// else
// {
// print('Can't log in. Please try again later');
// }
}
// }
}
};
document.addEventListener('DOMContentLoaded', function () {
console.log('dom content loaded');
window.PC = new AssumeIdentityController();
});
Permissions in manifest look like this:
...
"permissions": [
"browsingData","declarativeContent","storage","https://*/","http://*/"
],
...

How to prevent error being displayed in NetSuite?

I am writing a script to take a value from one field and place it into a list field in NetSuite. I believe the issue is because upon saving the record a value is trying to be set in a list that does not contain that value.
I want this to fail silently when set within the context of my script, how can I prevent the error message from showing up and allow the record to be created but without that field being populated?
Scenario - Value is placed into this field, the script tries to map that value to a list value (IT DOES NOT EXIST), the record should still save, but without that data being set - NO ERRORS.
/**
* #NApiVersion 2.x
* #NScriptType UserEventScript
* #NModuleScope SameAccount
*/
define(['N/record', 'N/log'],
/**
* #param {record} record
*/
function(record) {
function customer_beforeLoad(scriptContext) {
}
function customer_beforeSubmit(scriptContext) {
//Segment
setNonIntegrationFieldValue(scriptContext, 'custentity_cus_segmentintegration', 'custentity_cus_segment');
//Currency
setNonIntegrationFieldValue(scriptContext, 'custentity_cus_primarycurrencyintegratio', 'currency');
//Billing Cycle
setNonIntegrationFieldValue(scriptContext, 'custentity_cus_billingcycleintegration', 'custentity_cus_billingcycle');
//Type
setNonIntegrationFieldValue(scriptContext, 'custentity_cus_typeintegration', 'custentity_cus_type');
//Industry
setNonIntegrationFieldValue(scriptContext, 'custentity_cus_industryintegration', 'custentity_esc_industry');
//Sales Rep
setNonIntegrationFieldValue(scriptContext, 'custentity_cus_salesrepintegration', 'salesrep');
}
function customer_afterSubmit(scriptContext) {
}
function setNonIntegrationFieldValue(scriptContext, integrationFieldName, actualFieldName){
try {
var integrationFieldValue = scriptContext.newRecord.getValue(integrationFieldName);
if(integrationFieldValue == '' || integrationFieldValue == null){
scriptContext.newRecord.setValue({
fieldId: actualFieldName,
value: ''
});
} else {
scriptContext.newRecord.setText({
fieldId: actualFieldName,
text: integrationFieldValue
});
}
} catch(e){
log.error({
title: "setNonIntegrationFieldValue() has encountered an error.",
details: e.message
});
//nlapiLogExecution('ERROR','setNonIntegrationFieldValue() has encountered an error.', errText(e));
}
}
return {
//beforeLoad: customer_beforeLoad,
beforeSubmit: customer_beforeSubmit,
//afterSubmit: customer_afterSubmit
};
});
I think the solution should not be preventing a message from showing up, instead, it should be preventing setting of the value when it's not a valid value. You can try firstly get the array of all valid options in that list, secondly check if the value you want to use is contained in the array, if yes then set the value.
To be specific:
var actualField = scriptContext.form.getField(actualFieldName);
var options = actualField.getSelectOptions();
var integrationFieldValue = scriptContext.newRecord.getValue(integrationFieldName);
if (options.indexOf(integrationFieldValue) > -1) {
scriptContext.newRecord.setText({
fieldId: actualFieldName,
text: integrationFieldValue
});
}
For more details for the function getSelectOptions, please refer to Netsuite Help center (search Field.getSelectOptions)
Just wrap ANY AND ALL netsuite logic with a try catch. We have over 614,00 LOC in netsuite and this works 100%:
try {
// your code here
} catch (e) {
// this ternary operator will catch all the ns errors. you can fail silently here
var error = e.details || e.message || e.toString();
throw error;
}

Convert IIFE module to something importable by RollupJS

I am using RollupJS as a bundler, and it can read CommonJS (via a plugin) or ES6 modules. But this module seems to be in UMD format, and I am looking for a quick way I can edit it (without replacing a lot of lines) so that it is in commonJS or ES6 format.
What do folks suggest? I show the top and the bottom of a 5,000 line .js file.
#module vrlinkjs
**/
(function (mak) {
mak.MessageKindEnum = {
Any : -1,
Other : 0,
AttributeUpdate : 1,
Interaction : 2,
Connect : 3,
ObjectDeletion : 4
};
/**
Decodes AttributeUpdate messages into an EnvironmentalStateRepository object.
#class EnvironmentalStateDecoder
#constructor
#augments StateDecoder
#param {WebLVCConnection} webLVCConnection Connection to a WebLVC server
**/
mak.EnvironmentalStateDecoder = function(webLVCConnection) {
mak.StateDecoder.apply(this, arguments);
};
mak.EnvironmentalStateDecoder.prototype = Object.create(mak.StateDecoder.prototype, {
constructor : { value : mak.EnvironmentalStateDecoder },
/**
Decodes a AttributeUpdate message into an EntityStateRepository object.
#method decode
#param {Object} attributeUpdate WebLVC AttributeUpdate message
#param {EntityStateRepository} stateRep State repository to be updated
**/
decode : {
value : function( attributeUpdate, stateRep ) {
// if(this.webLVCConnection.timeStampType == mak.TimeStampType.TimeStampAbsolute &&
// attributeUpdate.TimeStampType == mak.TimeStampType.TimeStampAbsolute) {
// } else {
// stateRep.timeStampType = mak.TimeStampType.TimeStampRelative;
// }
stateRep.timeStampType = mak.TimeStampType.TimeStampRelative;
var curTime = 0.0;
// if (stateRep->timeStampType() == DtTimeStampAbsolute)
// {
// // Use timestamp as time of validity
// curTime = pdu.guessTimeValid(myExConn->clock()->simTime());
// }
// else
// {
// // Use receive time as time of validity
// curTime = myExConn->clock()->simTime();
// }
curTime = this.webLVCConnection.clock.simTime;
if(attributeUpdate.ProcessIdentifier != undefined) {
stateRep.entityIdentifier = attributeUpdate.EntityIdentifier;
}
if(attributeUpdate.Type != undefined) {
stateRep.entityType = attributeUpdate.Type;
}
if(attributeUpdate.ObjectName != undefined) {
stateRep.objectName = attributeUpdate.ObjectName;
}
if(attributeUpdate.GeometryRecords != undefined) {
stateRep.GeometryRecords = attributeUpdate.GeometryRecords;
}
if(attributeUpdate.EnvObjData != undefined) {
if(attributeUpdate.EnvObjData.VrfObjName != undefined) {
stateRep.marking = attributeUpdate.EnvObjData.VrfObjName;
}
}
}
}
});
.....
} (this.mak = this.mak || {}));
UPDATE
I used the ES6 module solution from estus (below), which I really like. It solved the rollup bunding issue, but there is still a runtime error.
But there is a little more that needs to be done. I am getting this error with chrome. I have two varients of the HTML main.html file, one uses the bundle and the other just imports my es6 modules. The error occurs even when I am not using rollup and creating and using the bundle.
Uncaught TypeError: Cannot set property objectName of [object Object] which has only a getter
at mak$1.ReflectedEntity.mak$1.ReflectedObject [as constructor] (vrlink.mjs:818)
at new mak$1.ReflectedEntity (vrlink.mjs:903)
at mak$1.ReflectedEntityList.value (vrlink.mjs:1358)
at mak$1.WebLVCMessageCallbackManager.<anonymous> (vrlink.mjs:1155)
at mak$1.WebLVCMessageCallbackManager.processMessage (vrlink.mjs:1745)
at mak$1.WebLVCConnection.drainInput (vrlink.mjs:2139)
at SimLink.tick (SimLink.js:34)
This seems to be the offender when converting from IIFE modules to ES6. It says that there is no setter.
The code is not my creation, but it seemed like it should not have be a major effort to convert IIFE to ES6. The offending snippet is:
mak.VrfBackendStateRepository = function (objectName) {
/**
Unique string identifying entity
#property objectName
#type String
**/
this.objectName = objectName; //error generated on this line!
If you are wondering what this is, it is a object called mak.webLVConnection, which is created by this function in the IIFE code:
/**
Represents a connection to a WebLVC server.
clientName and port are required. webLVCVersion is optional (current version
supported by the WebLVC server will be in effect). serverLocation is optional
( websocket connection will be made to the host servering the javascript )
#class WebLVCConnection
#constructor
#param {String} clientName String representing name of the client federate
#param {Number} port Websocket port number
#param {Number} webLVCVersion WebLVC version number
#param {String} serverLocation Hostname of websocket server
**/
mak.WebLVCConnection = function (clientName, port, webLVCVersion, serverLocation, url) {
var self = this;
if (clientName == undefined) {
throw new Error("clientName not specified");
}
if (!(typeof clientName == "string" && clientName.length > 0)) {
throw new Error("Invalid ClientName specified");
}
if (port == undefined) {
throw new Error("Port not specified");
}
if (url == undefined) {
url = "/ws";
}
var websocket;
if (serverLocation == undefined) {
if (location.hostname) {
websocket = new WebSocket("ws://" + location.hostname + ":" + port + url);
}
else {
websocket = new WebSocket("ws://localhost:" + port + "/ws");
}
}
else {
websocket = new WebSocket("ws://" + serverLocation + ":" + port + url);
}
/**
Websocket connected to a WebLVC server.
#property websocket
#type WebSocket
**/
this.websocket = websocket;
/**
DIS/RPR-style identifier, used to generate new unique IDs for entities simulated
through this connection. Array of 3 numbers [site ID, host ID, entity number].
#property currentId
#type Array
**/
this.currentId = [1, 1, 0];
/**
Manages registration and invoking of message callbacks.
#property webLVCMessageCallbackManager
#type WebLVCMessageCallbackManager
**/
this.webLVCMessageCallbackManager = new mak.WebLVCMessageCallbackManager();
/**
Simulation clock
#property clock
#type Clock
**/
this.clock = new mak.Clock();
/**
Indicates whether timestamping is relative or absolute
(mak.TimeStampType.TimeStampRelative or
mak.TimeStampType.TimeStampAbsolute).
#property {Number} timeStampType
**/
this.timeStampType = mak.TimeStampType.TimeStampRelative;
/**
List of incoming messages. When messages are received, they are placed
in this queue. The drainInput() member function must be called regularly
to remove and process messages in this queue.
#property {Array} messageQueue
**/
this.messageQueue = new Array();
/**
Callback function invoked on receipt of a message. Calls
webLVCMessageCallbackManager.processMessage().
#method processMessage
#private
**/
this.processMessage = this.webLVCMessageCallbackManager.processMessage.bind(this.webLVCMessageCallbackManager);
/**
Callback function invoked when websocket connection is opened. Sends
the initial WebLVC connect message.
#method onopen
#private
**/
this.websocket.onopen = function () {
var connectMessage = {
MessageKind: mak.MessageKindEnum.Connect,
ClientName: clientName
}
if (webLVCVersion != undefined) {
connectMessage.WebLVCVersion = webLVCVersion;
}
if (self.websocket.readyState == 1) {
self.websocket.send(JSON.stringify(connectMessage));
}
};
/**
Callback function invoked when a WebLVC message is received. Parses the
the JSON message data and passes the resulting object to processMessage.
#method onmessage
#event {Object} JSON message
#private
**/
this.websocket.onmessage = function (event) {
//just in case
if (event.data == "ping")
return;
var message = JSON.parse(event.data);
if (message != null) {
self.messageQueue.push(message);
} else {
console.warn("onmessage - null message received");
}
};
/**
Callback function invoked when the websocket is closed.
#method onclose
#private
**/
this.websocket.onclose = function () {
console.debug("In websocket.onclose");
};
/**
Callback function invoked when an error in the websocket is detected.
Sends warning to console.
#method onerror
#private
**/
this.websocket.onerror = function () {
console.log("websocket onerror");
};
this.isOk = function () {
return this.websocket.readyState == 1;
}
};
mak.WebLVCConnection.prototype = {
constructor: mak.WebLVCConnection,
/**
Set the DIS/RPR-style application ID.
#method set applicationId
#param {Array} applicationId Array of 2 integers [site ID, host ID].
**/
set applicationId(applicationId) {
this.currentId[0] = applicationId[0];
this.currentId[1] = applicationId[1];
this.currentId[2] = 0;
},
/**
Returns next available DIS/RPR-style entity ID.
#method nextId
#return {Array} Array of 3 integers [site ID, host ID, entity number].
**/
get nextId() {
this.currentId[2]++;
return this.currentId;
},
/**
Register callback function for a given kind of message.
#method addMessageCallback
#param {Number} messageKind WebLVC MessageKind
#param callback Function to be invoked
**/
addMessageCallback: function (messageKind, callback) {
this.webLVCMessageCallbackManager.addMessageCallback(messageKind, callback);
},
/**
De-register callback function for a given kind of message.
#method removeMessageCallback
#param messageKind WebLVC MessageKind
#param callback Function to be invoked
**/
removeMessageCallback: function (messageKind, callback) {
this.webLVCMessageCallbackManager.removeMessageCallback(messageKind, callback);
},
/**
Send a WebLVC message to the server.
#method send
#param {Object} message
**/
send: function (message) {
try {
if (this.websocket.readyState == 1) {
this.websocket.send(JSON.stringify(message));
}
} catch (exception) {
console.log("Error sending on websocket - exception: " + exception);
}
},
/**
Send a time-stamped WebLVC message to the server.
#method sendStamped
#param {Object} message
**/
sendStamped: function (message) {
// Timestamp is hex string
var timeStamp = this.currentTimeForStamping().toString(16);
//message.TimeStamp = ""; // timeStamp;
this.send(message);
},
/**
Get the current simulation time for a time stamp.
#method currentTimeForStamping
#return {Number} Simulation time in seconds.
**/
currentTimeForStamping: function () {
if (this.timeStampType == mak.TimeStampType.TimeStampAbsolute) {
return this.clock.simTime();
}
else {
return this.clock.absRealTime();
}
},
/**
Iterate through message queue, calling processMessage() and then
removing each message. Should be called regularly from your
application.
#method drainInput
**/
drainInput: function () {
var message;
while (this.messageQueue.length > 0) {
message = this.messageQueue.shift();
this.processMessage(message);
}
},
/**
Closes the websocket connection. Calls the destroy method on its
WebLVCMessageCallbackManager data member.
#method destroy
**/
destroy: function () {
console.debug("In WebLVCConnection.destroy");
this.webLVCMessageCallbackManager.destroy();
this.websocket.close();
}
};
UMD modules, by definition, are CommonJS. The code above is just IIFE and relies on mak global.
IIFE wrapper function can be replaced with default or named ES module export:
const mak = {};
mak.MessageKindEnum = { ... };
...
export default mak;
Or with CommonJS export:
const mak = {};
mak.MessageKindEnum = { ... };
...
module.exports = mak;
did you try:
(function (mak) {
...
}(module.exports));
// instead of
// } (this.mak = this.mak || {}));

Verifying sendKeys result in a Page Object file results in undefined error (Protractor)

So, I have a page object file that provides a number of methods for the elements on a page. The page is a login page with some text, a username and password input elements, and a login button. I've created a generic object called "InputLabel.js" which ties the label and input element together for testing purposes.
The problem I'm having is that after I clear the input, send the data, and then verify the data, I'm getting a Failed: Cannot read property 'verifyValue' of undefined error.
Here is the relevant code:
// InputLabel.js
function InputLabel(container) {
this.Container = container;
}
InputLabel.prototype = {
constructor: InputLabel,
// ...
/**
* Return the element for the input of the input/label combination of elements.
*
* #returns {ElementFinder}
*/
getInput: function () {
return this.Container.$('input');
},
/**
* Return the text shown in the input of the input/label combination of elements.
*
* #returns {Promise}
*/
getValue: function () {
return this.getInput().getAttribute('value');
},
/**
* Verify the text shown in the input of the input/label combination of elements.
*
* #param expected The expected text in the input element.
*/
verifyValue: function (expected) {
console.log('Asserting input value [' + expected + ']');
expect(this.getValue()).toEqual(expected);
},
// ...
/**
* Clears the input element then puts the text from data into the input element.
*
* #param data The text to be entered into the input element.
*/
sendKeys: function (data) {
var el = this.getInput();
el.clear().then(function () {
el.sendKeys(data).then(function () {
console.log("Verifying [" + data + "] was sent to the input.")
this.verifyValue(data);
});
});
}
};
After requiring the file, I can call any of these methods without issue except the sendKeys. If I disabled the this.verifyValue(data); method, sendKeys works fine.
// LoginPage.js
var InputLabel = require('InputLabel.js');
function LoginPage() {
}
var username = new InputLabel($('#username'));
var password = new InputLabel($('#password'));
function.prototype = {
// ...
username: username,
password: password,
loginButton: {
get: function() { return $('#Login'); },
click: function() { return this.get().click(); }
},
// ...
login: function(user, pw) {
this.username.sendKeys(user);
this.password.sendKeys(pw);
this.loginButton.click()
}
}
Am I losing something in scope? Again, the error is that it fails because it cannot read property 'verifyValue' of undefined after sending the keys.
You have a scoping issue with "this" keyword on the line containing "this.verifyValue(data);". In this case "this" keyword doesn't refer to the InputLabel class. Also it is considered a good practice to keep page objects assertion-free. See http://martinfowler.com/bliki/PageObject.html

Categories

Resources