Running Raygun.io with Angular Universal - javascript

I'm adding Raygun.io APM to our Angular 8 app with Angular Universal.
It is known that raygun.io has a client side javascript library and to add this to a Angular with Universal, DOM window API must be created. This can be done using domino npm using this code below:
There is also an installation guide for Angular via npm called raygun4js however the problem still exists.
// Domino for defining Windows API in SSR
(found # https://www.npmjs.com/package/domino )
const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs.readFileSync(index.html).toString();
const win = domino.createWindow(template);
global['window'] = win; // will be used for NodeJS to read Window API
global['document'] = win.document;
*domino creates a window api and sets it to a global called win.
After adding this line to an NPM project server.ts, build and run command - an exception is found:
Raygun.Utilities = raygunUtilityFactory(window, Raygun);
^
ReferenceError: raygunUtilityFactory is not defined
This roots that a raygunUtilityFactory function is not defined within window API. Looking inside raygun.js in Github
window.raygunUtilityFactory = function(window, Raygun) {
var rg = {
getUuid: function() {
function _p8(s) {
var p = (Math.random().toString(16) + '000000000').substr(2, 8);
return s ? '-' + p.substr(0, 4) + '-' + p.substr(4, 4) : p;
}
// more code.....
Question is, how can NodeJS read raygunUtilityFactory function during build if it can't find it in window API?
UPDATE: I tried to do this on a smaller project but it seems that even its document for installing raygun.io doesn't include procedures for Angular Universal. It basically can't detect window API using domino
Raygun.Utilities = raygunUtilityFactory(window, Raygun);
^
ReferenceError: raygunUtilityFactory is not defined

Answer: Setting Raygun js as a global object and referencing it to a declared variable inside a service.
Reference: https://hackernoon.com/how-to-use-javascript-libraries-in-angular-2-apps-ff274ba601af
declare var rg4js: any;
*place this inside your service or your main component ts.
<script type="text/javascript">
!function(a,b,c,d,e,f,g,h){a.RaygunObject=e,a[e]=a[e]||function(){
(a[e].o=a[e].o||[]).push(arguments)},f=b.createElement(c),g=b.getElementsByTagName(c)[0],
f.async=1,f.src=d,g.parentNode.insertBefore(f,g),h=a.onerror,a.onerror=function(b,c,d,f,g){
h&&h(b,c,d,f,g),g||(g=new Error(b)),a[e].q=a[e].q||[],a[e].q.push({
e:g})}}(window,document,"script","//cdn.raygun.io/raygun4js/raygun.min.js","rg4js");
</script>
*add this to your index.html or download and add it to your project.
Do take note that the raygun script should be referenced as rg4js.
Angular will automatically know that the rg4js inside your TS file is reference to your raygun script tag.
-- I'm now able to see the crash reporting and the pulse monitoring inside our client dashboard. However, I noticed that all client side errors logs are not caught. I'm still researching way to send these unhandled errors - starting with windows.onerror.

Good to hear you have figured out part of the solution!
AngularJS captures a lot of errors under the hood automatically and to properly capture errors you will need to register your own angular error handler and when the callback is fired you can use the Raygun4JS send method to send the message to Raygun.
export class RaygunErrorHandler implements ErrorHandler {
handleError(e: any) {
rg4js('send', {
error: e,
});
}
}
Raygun has a little bit of angular documentation but can't import raygun4js via npm for Angular Universal (as per your discovery) so you will need to modify the examples shown. That said they should provide a good starting point.

Related

Webdriver.io - Unable to load spec files quite likely because they rely on `browser` object

I'm using Webdriver.io to run tests on a large number of pages. Because all the specs for the pages are in a JSON file, I have a special class that sets up the test. It looks like this:
module.exports = class PageTester {
suiteName = '';
browser = {};
constructor (suiteName, browser) {
this.suiteName = suiteName;
this.browser = browser;
}
testModel(currentModel) {
describe(this.suiteName + ' endpoint ' + currentModel.url, () => {
this.browser.url(currentModel.url);
/* it() statements for the test */
});
}
}
Then in my specs folder I have a file that loads the JSON and plugs it into the PageTester class, like this:
const PageTester = require('../modules/PageTester');
const models = require('/path/to/some/file.json');
const pageTester = new PageTester('Some Name', browser);
for (const modelName in models) {
pageTester.testModel(models[modelName]);
}
When I run this code, WebdriverIO gives me the following warning:
WARN #wdio/mocha-framework: Unable to load spec files quite likely because they rely on `browser` object that is not fully initialised.
`browser` object has only `capabilities` and some flags like `isMobile`.
Helper files that use other `browser` commands have to be moved to `before` hook.
Spec file(s): /suite/test/specs/test.js
All the tests seem to run fine, so I don't actually understand what this warning is complaining about and what negative consequences ignoring it may have. So I would like to a) understand why this is happening and b) how it would be possible to get rid of this warning given the way my code is set up.
In my case, I resolve it by fixing the path for the require files. I noticed that my path was wrong. But the error that wdio throws is not really helpful. :/
you can only interact with browser object inside it blocks because it is not fully accessible before the browser session is started.
See https://webdriver.io/blog/2019/11/01/spec-filtering.html for details.
You simply should ensure your spec file and respective page file are kept on a similar folder structure.

how to use require function in js

I get properly credit card info upon input done I called a function to validate credit card with luhn module ( npm install luhn) as I use :
var luhn = require("luhn");
is_valid = luhn.validate(card); // should respond true.
if (!is_valid) {
console.log("Not a valid credit card");
}
return;`
Uncaught ReferenceError: require is not defined
I am sorry If this is simple question but since I could not find a logic short solution for npm packed usage. onsubmit I call this time kkTahsil() function.
function kkTahsil() {
datalariAl();
var Iyzipay = require('iyzipay');
var iyzipay = new window.Iyzipay({
apiKey: 'sandbox-PZ8jicWrEeE1rt1O75FTOegr5lsW3xxx',
secretKey: 'sandbox-2Q6aaP1FK3HFrXkTsHfftxfiudFMfxxx',
uri: 'https://sandbox-api.iyzipay.com'
});
var nameOnCard = document.getElementById('name-on-card').value;
var expireMonth = document.getElementById('card-exp-month').value;
var expireYear = document.getElementById('card-exp-year').value;
var cvc= document.getElementById('card-cvv').value;
again same error.
so in js, there must be easy way to use npm modules. But I could not found yet.
Please I need a help.
require is not available in the browser. It is used in Node.js.
If you want to use require on the client side then use Browserify:
Browserify lets you require('modules') in the browser by bundling up all of your dependencies.
In fact, require couldn't be available in the browser in the form as it is implemented in Node. The problem with require is that it is synchronous. It works on the server side on the first tick of the event loop when you can block on I/O because no event listeners are bound yet, but it will not work in the browser without problems because it would have to block the UI for the entire time that the modules are downloaded, compiled and run.
In fact synchronous vs asynchronous module loading has been a matter of controversy. See those answers for more details:
Exporting Node module from promise result
javascript - Why is there a spec for sync and async modules?

Firefox add-on. How to really dowload image/file?

I'm getting more and more downhearted. For the last three days, I've been trying to add to my simple Firefox add-on a 'download image' feature.
The following is an add-on that creates a right-click contextual menu with a sub-menu:
var contextMenu = require("sdk/context-menu");
var clipboard = require("sdk/clipboard");
var data = require("sdk/self").data;
var myApp_cm = contextMenu.Menu({
label: "Send to myApp",
context: contextMenu.SelectorContext("body"),
items: [
contextMenu.Item({
label: "Send image to MyApp",
context: contextMenu.SelectorContext("img"),
contentScript: 'self.on("click", function (node, data) { ' +
' var link = node.src; ' +
' self.postMessage(link); ' +
'});',
onMessage: function(link) {
//
// Download image from 'link' and run 'myApp.exe' with
// downloaded image as parameter
//
}
})
]
});
I would like to add to the above code a simple download feature as the "Save as..." option of Firefox that downloads the image from the selected URL and runs an EXE with the downloaded image as a parameter.
I read everything I found about this argument starting from Mozilla MDN to all the questions asked at Stackoverflow. But, I never managed to make a single line of code work. I really don't understand why it's so complicated to download a file when this is the browser's job.
For example, I know that from Firefox 26+ I need to use downloads.jsm. So, I copied the following code from MDN.
Components.utils.import("resource://gre/modules/Downloads.jsm");
Components.utils.import("resource://gre/modules/osfile.jsm")
Components.utils.import("resource://gre/modules/Task.jsm");
Task.spawn(function () {
yield Downloads.fetch("http://www.mozilla.org/",OS.Path.join(OS.Constants.Path.tmpDir,"example-download.html"));
console.log("example-download.html has been downloaded.");
}).then(null, Components.utils.reportError);
But, I keep getting the error below:
So I added the string let {Cu, Ci, CC} = require('chrome') but nothing changes.
I'm 43 years old and I'm still learning JavaScript. I'm aware I don't have the same flexibility I had 2 decades ago. But, I remember that programming was much more straightforward. I still love programming but now I often find it quite frustrating.
I have not actually tried it, but I would not not expect the destructuring assignment
let {Cu, Ci, Cc} = require('chrome');
[Note: your CC should be Cc.]
to provide your Add-on SDK code to have access to the complete Components object through referencing it as Components, but only to have the properties (sub-objects) which you have assigned to "aliases" be available through the objects that you have defined using let:
Object ("alias") now available Object full name normally available
to your SDK add-on to Overlay and Restartless add-ons
Cu = Components.utils
Ci = Components.interfaces
Cc = Components.classes
The destructuring assignment should have extracted just the properties (sub-objects) referred to as Cu, Ci, and Cc within requre('chrome').
The code you copied from MDN would need to change to:
Cu.import("resource://gre/modules/Downloads.jsm");
Cu.import("resource://gre/modules/osfile.jsm")
Cu.import("resource://gre/modules/Task.jsm");
Task.spawn(function () {
yield Downloads.fetch("http://www.mozilla.org/",
OS.Path.join(OS.Constants.Path.tmpDir,"example-download.html"));
console.log("example-download.html has been downloaded.");
}).then(null, Cu.reportError);
If you wanted to use Components without using the Cc, Ci, Cu, Cr, and Cm aliases, you would need to use:
let {components} = require('chrome'); // note the lowercase "components"
let Components = components;
With that you could then use your original code:
Components.utils.import("resource://gre/modules/Downloads.jsm");
Components.utils.import("resource://gre/modules/osfile.jsm")
Components.utils.import("resource://gre/modules/Task.jsm");
Task.spawn(function () {
yield Downloads.fetch("http://www.mozilla.org/",
OS.Path.join(OS.Constants.Path.tmpDir,"example-download.html"));
console.log("example-download.html has been downloaded.");
}).then(null, Components.utils.reportError);
For more information, you can see the Chrome Authority page on MDN.
So, I copied the following code from MDN.
This is a big part of your problem. You're copying code without reasoning about it. Code snippets generally have prerequisites and assumptions that must be fulfilled, i.e. they must be evaluated on specific contexts - npm modules won't run in a browser for example.
Those code snippets too have dependencies, e.g. the Components object. The error message warns you about that, so that might be a good hint to read the documentation on require("chrome") and Components.
The second issue is that you're trying to use JSMs in an SDK addon without looking for equivalent SDK APIs first. Note that the top-level MDN Addon page distinguishes several types of extensions, especially SDK and legacy extensions. You're writing an SDK extension.
So for the purpose of downloading images instead of going through the file download manager (Downloads.jsm) you can simply use the request and IO SDK modules to download the file and then child_process to spawn the exe.
Task.spawn(function () {
yield Downloads.fetch("http://www.mozilla.org/",
That's using yield outside a generator function, which is legacy syntax and should not be used.
For chaining you probably should use ES6 promises instead.

Object #<Object> has no method 'getInstance' when trying to run Protractor tests

When I am attempting to run my Protractor tests from the command line all of my tests fail because whenever I try to access the protractor object it does not have the methods I need. The exact error is:
TypeError: Object # has no method 'getInstance'
So this seems to have been a reported and fixed issue, yet I cannot seem to resolve my particular situation. It also seems to be semi-related to this question, but because it arose for me after updating my node_modules I feel like my underlying issue is different. Up until updating my Protractor everything worked just fine.
I installed it globally and used npm link protractor to link my local instance to my global instance (located at /usr/local/lib/node_modules/protractor), but I still for the life of me cannot figure out what is wrong.
The exact code where I'm calling protractor is a page object file that looks like:
module.exports = function() {
var ptor = protractor.getInstance();
this.get = function() {
browser.get('http://localhost');
this.title = ptor.getTitle();
};
};
The code instantiating the page object is as follows:
var Login = require('./pageObjects/Login.po.js');
...
var LoginPage = new Login();
You don't need to call protractor.getInstance() anymore, use globally-available browser object:
this.title = browser.getTitle();
And, yes, this was a breaking change in 1.5.0, see:
Breaking Changes

Include libraries in Protractor test case

I would like to include a module/library in a protractor test case, however, as soon as I add the line
var lib = require('./loginactions.js');
All the references to protractor and related objects are lost. In other words, if I don't have the require line, the 'protractor' and 'browser' variables are found and test runs fine (using the functions within the file), but after adding that line the variables are not found any more.
Here is a minimal test case:
var lib = require('./loginactions.js'); //problematic line
describe('Login / Logout to Application',function(){
var ptor;
beforeEach(function(){
ptor = protractor.getInstance(); //protractor reference lost
browser.get('http://localhost:80'); //browser reference lost
});
it('should login and then logout successfully', function(){
//Do things here
lib.login(user, pass, ptor);
});
});
I export the functions in this way:
module.exports.Login = Login;
module.exports.Logout = Logout;
//Params: ptor - protractor instance
function Login(user, pass, ptor)
{
//stuff
}
function Logout(ptor)
{
//stuff
}
I also wonder, is this even the correct way of including the own libraries into the project. So my question is, how to properly include libraries into a protractor test case?
To answer my own question, using protractor as a library method worked, this way the references to protractor were restored. So adding these two requires solved my issue:
var protractor = require('/path/to/protractor');
require('/path/to/protractor/jasminewd');
So my test looked similar to the updated code in
'no method expect' when using Protractor as a library question.
However, I am not entirely sure about the global browser object. It is a wrapper around the WebDriver object according to http://www.ng-newsletter.com/posts/practical-protractor.html, but so is protractor instance. So I decided to replace all 'browser' variables with 'ptor' and so far no complaints. This may backfire, but as I said, I'm not entirely sure whether the global browser object that is created along with the global protractor object, when running protractor normally and not as library.

Categories