AddonSK: how can window from require('sdk/window/utils').openDialog interact with main.js script? - firefox-addon-sdk

I am writing a FF addon SDK plugin.
My main.js opens a popup window with :
var win = require('sdk/window/utils').openDialog({
url:"http://www.example.com/index.html",
features: Object.keys({
resizable: true,
scrollbars: true
}).join(),
name: "myWin"
});
I need the window to send data to the main.js (index.html is an external HTTP classical html/JS page)

1: add a content script.
using pageMod or tabs API, inject a js file in to the http://www.example.com/index.html page.
2: sending message from the content script, then add an message listener in the main.js

In main.js:
var tab = win.tabs[0]; // as it is a pop-up window I assume it has only one tab
// attach content script to tab and access worker object
var worker = tab.attach({
contentScriptFile: self.data.url('popup_window_script.js'), // script from file
contentScript: '' // and/or script from string
});
// listen to worker / popup_window_script.js
worker.port.on('msg_from_popup_window_script_js', function ( msg ) {
// your code
});
// speak to worker / popup_window_script.js
worker.port.emit('msg_from_main_js', 'your message');
In popup_window_script.js:
// listen (to main.js)
self.port.on('msg_from_main_js', function ( msg ) {
// your code
});
// speak (to main.js)
self.port.emit('msg_from_popup_window_script_js', 'your message');

Related

Why is the web worker api not working in react even in the simplest implementation?

I created a toy mern app which can upload images to mongodb. It works fine in the development but after I deploy to heroku, I get a timeout error. After doing a fair amount of investigations I come to the conclusion that web workers will help sort this out. So I've done this:
This is a snippet from the component that takes care of sending this request, to upload an image:
const handleUploadPhoto = evt => {
evt.preventDefault();
const worker = new Worker('imageUpload.js');
worker.postMessage(selectedPhotos);
worker.onmessage = evt => console.log(evt.data);
closeModal();
};
This whole component is actually a modal, and after I submit this handleUploadPhoto function the modal closes. Notice the closeModal function;
In the same folder as this component I have the imageUpload.js worker file:
self.addEventListener('message', evt => {
const { selectedPhotos } = evt.data;
selectedPhotos.map(photo => {
const formData = new FormData();
formData.append('photo', photo);
fetch( `/api/photo/upload/${JSON.parse(localStorage.getItem('loggedUser'))._id}`, {
method: 'POST',
body: formData,
headers: ['Content-Type', 'multipart/form-data'],
}).then(() => console.log('OK'));
});
self.postMessage(evt.data);
});
The idea behind this functionality is that I select one or more images, then I map through them and send a post request to the server with each image as formData. So I thought to move the request to a worker so that it doesn't break my UI anymore. Needless to say that it doesn't work and it gives net::EMPTY_RESPONSE error after some seconds. What I also noticed is that the worker doesn't communicate with the file it was issued in at all. I tried to make a text message pop in the console:
const handleUploadPhoto = evt => {
evt.preventDefault();
const worker = new Worker('imageUpload.js');
worker.postMessage('Hello');
worker.onmessage = evt => console.log(evt.data);
closeModal();
};
In the same folder as this component I have the imageUpload.js worker file:
self.addEventListener('message', evt => {
self.postMessage(evt.data + ' world');
});
It doesn't work. I tried the same approach in a separate project and it worked.
How can I make an HTTP request do what it's supposed to do from a web worker?

How to perform beforeTest and afterTest method using typescript (protractor+cucumber)

Framework used - Protractor
BDD - Cucumber
Language - Typescript
Now i have implemented the framework and a test scenario is also running fine with protractor.
But the problem i am facing is when i write another cucumber scenario my test fails saying 'A session is either terminated or not started'
The above failure is because when my first cucumber scenario starts the appium server starts with in my config and at the end i close the server/driver
Now i have written another test scenario, since cucumber is independent of each scenario , when the sec starts it does not do the config again. Now i need a beforeTest method to call.
So i am not sure how to implement that in typescript,as i am new to it.
Tried the same concept of java way but not working out. There where examples for javascript but still did not help me out.
Tried creating a new util folder and placing my beforeTest inside that but the function is not calling there
Tried to use beforeLaunch()with in my config file, but still does not work out
my config file: config.ts
export let config: Config = {
allScriptsTimeout: 40000,
getPageTimeout: 40000,
setDefaultTimeout: 60000,
defaultTimeoutInterval: 30000,
specs: [
// '../../utils/beforeEach.ts',
'../../features/*.feature',
],
onPrepare: () => {
Reporter.createDirectory(jsonReports);
tsNode.register({
project: './tsconfig.json'
});
},
multiCapabilities: [
androidPixel2XLCapability,
// iPhoneXCapability
],
framework: 'custom',
frameworkPath: require.resolve('protractor-cucumber-framework'),
cucumberOpts: {
compiler: "ts:ts-node/register",
glue: ["steps"],
format: [
"json:./reports/json/cucumber_report.json",
],
require: ['supports/timeout.js', '../../stepdefinitions/*.ts'],
tags: "#firstPurchasePopup",
},
seleniumAddress: serverAddress,
onComplete: () => {
Reporter.createHTMLReport();
},
// =====
// Hooks
// =====
beforeTest: function () {
},
beforeLaunch(){
console.log("Before");
seleniumAddress: 'http://localhost:4723/wd/hub';
},
afterLaunch() {
console.log("After");
},
};
my other beforeEach.ts:
This is not working but what i tired and was not working.
import {After, AfterAll, Before} from "cucumber";
const serverAddress = 'http://localhost:4723/wd/hub';
import {beforeEach, afterEach, describe} from "selenium-webdriver/testing";
beforeEach(function () {
console.log("Before");
});
// });
afterEach(function () {
console.log("Before");
});
// let beforeEach: () => void;
// beforeEach = () => {
// console.log("Before Test");
// // config.multiCapabilities;
// seleniumAddress: serverAddress;
// };
//
// let afterEach: () => void;
// afterEach = () => {
// console.log("After Test");
// };
This is my feature file: bonus.feature
this is my feature file:
Background:
Given I launch the app
Then I should see the popup window for the Bonus
And I verify the UI
Then I tap on ok button
And The popup window should not be seen
#firstPurchasePopup
Scenario: firstPurchasePopup new join button
When I tap on the 'New ' button
And The popup window should not be seen
Then I navigate back from join page to home page
Then The popup window should not be seen
Then I close the app
#firstPurchasePopup
Scenario: firstPurchasePopup login button
And I tap on log in button on the initial screen
Then I navigate back from login page to home page
And The popup window should not be seen
Then I close the app
I expect my the scenario what i have written to execute both one after the other , like execute Scenario: firstPurchasePopup new join button which it does . But when it launches the app again for the sec Scenario: firstPurchasePopup login button does not work as the driver is not started again, since it was closed in prev one.
to start it i need to create beforeTest which i am facing difficutly to write the code
I haven't used Protractor with Cucumber, but I have used Cucumber & Typescript together. I resolved the problem by having a file cucumber.js in a root that is being loaded at the very beginning by default and looks like that:
var settings = "features/**/*.feature -r step-definitions/**/*.ts -r hooks/**/*.ts -r support/**/*.ts "
module.exports = {
"default": settings
}
However, I think in your case the solution would be adding a path to hooks file to config.cucumberOpts.require list instead to config.specs one.
Did you try it?
#All
Thanks for your inputs #mhyphenated
I figured out that the rather than using inside the config, i tried using the before and after in the hooks.ts ,also other than calling the server i was not actually calling the android driver, as below and that worked
beforeTest: function () {
beforeTest: function () {
},
beforeLaunch(){
console.log("Before");
seleniumAddress: 'http://localhost:4723/wd/hub';
},
hooks.ts
import { AndroidDriver } from "appium/node_modules/appium-android-driver";
let driver:AndroidDriver, defaultCaps;
driver = new AndroidDriver();
Before(function () {
// This hook will be executed before all scenarios
browser.ignoreSynchronization = false;
browser.manage().timeouts().implicitlyWait(500);
let defaultCaps = config.multiCapabilities[0];
console.log("defaultCaps = ", defaultCaps );
driver.createSession(defaultCaps);
driver.defaultWebviewName();
});

Name with gear icon in Chrome network requests table

(30119999.xml in pic1, has a gear mark pre name)
I set this request in Web Worker, response data is ok and I terminated it in onmessage callback
but why the request always in pending and can't preview, please help.
pseudocode:
const workerBlob = new Blob([`onmessage = function (event) {
const xhr = new XMLHttpRequest();
xhr.addEventListener('load', function () {
postMessage(xhr.response);
});
xhr.open('GET', event.data.url, true);
xhr.send();
}`], { type: 'application/javascript' });
const workerURL = URL.createObjectURL(workerBlob);
const worker = new Worker(workerUrl);
worker.postMessage({url});
worker.onmessage = (message) => {
// do something
worker.terminate();
};
According to Debugging Service Workers :
The gear icon signifies that these requests came from the Service
Worker itself. Specifically, these are the requests being made by the
Service Worker's install handler to populate the offline cache.
Make sure you are not terminating your worker too fast. You should terminate the Worker when the loadend event has fired.

Dancer2 application: streaming content blocks server and client. How to avoid blocking?

tl;dr
I'm streaming content with Dancer2's keywords delayed, flush, content, done and it blocks the server while streaming until I call done. How can I avoid that?
More detailed
I wrote a Dancer2 application that calls an external command (a shell/Perl script) when the user hits a specific button. I want the output of that command to appear in the browser in a <pre> section and I want to refresh that section as new lines arrive. Similar to a tail -f but in the browser. My external command runs several seconds, possibly up to 10 minutes, so I run it asynchronously.
My first approach was to completely detach the program from the Webserver using double-fork, exec, ssid, and closing/reopening the program's STDIN/OUT/ERR so that the command's output goes to a temporary logfile. Then I set up AJAX calls (one per second) so that my Dancer2 application reads the new lines from the logfile and returns them to the client until the PID of the external command would disappear. This worked like a charm until the moment when my "external command" issued ssh commands to contact some other server and return that output as well. ssh doesn't work properly when run without a terminal and the ssh did not produce any output. Think of ssh $host "ls -l", which gave no output.
So I switched to Dancer2's delayed mechanism like shown in the code below. I took the CSV example from the Dancer2 docs as a template. Again, it works like a charm, but while the command is running and new lines appear in the browser, the server is blocked. When I click some other link on the Webpage, I only see an hour glass until the command is over. It looks like the server is single-process and single threaded.
index.tt
<script>
function start_command( event ) {
$('#out_win').empty();
var last_response_len = false;
$.ajax({
url: '/ajax/start',
xhrFields: {
onprogress: function(evt){
/* make "this_response" only contain the new lines: */
var this_response;
var response = evt.currentTarget.response;
if ( last_response_len === false ) {
this_response = response;
last_response_len = response.length;
} else {
this_response = response.substring(last_response_len);
last_response_len = response.length;
}
/* add those new lines to <pre> and scroll down */
var pre = $('#out_win');
pre.append(this_response);
pre.scrollTop(pre.prop('scrollHeight'));
}
},
success: function(result, textStatus, jqXHR) {
alert("Done streaming, result="+result);
},
error: function( jqXHR, textStatus, errorThrown ) {
alert("error; status=" + textStatus);
},
});
event.preventDefault();
}
</script>
<div class="container">
<div> <%# Links %>
Start external command</br>
Show some other page
<div>
<div> <%# output window %>
<pre class="pre-scrollable" id="out_win"></pre>
</div>
</div>
Streaming.pm
package Streaming;
use Dancer2;
################################################################
#
################################################################
get '/' => sub {
template 'index';
};
################################################################
#
################################################################
get '/ajax/start' => sub {
delayed {
flush; # streaming content
# "stream" something. Actually I start an external program here
# with open(..., "$pgm |") and stream its output line my line.
foreach my $line ( 1 .. 10 ) {
content "This is line $line\n";
sleep(1);
}
done; # close user connection
}
on_error => sub {
my ($error) = #_;
warning 'Failed to stream to user: ' . request->remote_address;
};
};
true;
I'm using
Dancer2 0.204002 as installed via apt install libdancer2-perl on
Ubuntu 17.04
no further Webserver, i.e. I'm using the server that ships with Dancer2, started with plackup -a bin/app.psgi
jQuery 2.2.4
Bootstrap 3.3.7
Perl 5.18+
My questions are:
Am I doing something completely wrong wrt. the delayed keyword?
Or am I using the wrong Webserver for this task? I'd love to stick with
the Webserver that comes with Dancer2 because it's so simple to use and
I don't need a throughput like e.g. Google does. We will have 1-3 users
a day and mostly not at the same time, but a blocking Webapplication
would be a no-go.

Require: Doesn't find a file (Page Object Pattern)

I'm trying to incorporate the Page Object pattern in my Protractor testing but for some reason I don't know it's not working. I must say that before doing any change, everything was running perfect.
In test folder I have the file test.spec.js with this:
'use strict';
var LoginPage = require('../pages/login.page.js');
describe('Login --> ', function(){
'use strict';
var ptor;
var page;
beforeEach(function () {
page = new LoginPage();
ptor = protractor.getInstance();
ptor.waitForAngular();
});
describe('False Login --> ', function(){
it('It should be false login with PIN --> ', function(){
/* some code */
});
});
});
and in same folder I got another one called "pages" and inside of it the file login.page.js. But when I run tests it doesn't find login.page.js.
"Error: Cannot find module '../pages/login.page.js'"
Anyone knows why?
Thanks guys ;)
If the folder pages is located in the same folder as test.spec.js you have to use require('./pages/login.page.js');