Debugging Worker thread in electron - electron

I'm testing out worker_thread on an electron application. I'm currently using version 11.0.2.
The code is simple and is working and returning the sample data but I cant seem to step into the code.
Main Process:
import { Worker, isMainThread, workerData } from 'worker_threads';
config.ipcMain.on('entries:search', (evt: any, opts: any) => {
if (isMainThread) {
const pathWorker = path.join(__dirname, '../data/entries_worker.js');
const worker = new Worker(pathWorker, {
workerData: opts.value,
});
worker.on('message', (data) => {
debugger;
const d = 1;
});
worker.on('error', (data) => {
debugger;
const d = 1;
});
worker.on('exit', (data) => {
debugger;
const d = 1;
});
}
});
The worker file code:
import { workerData, parentPort } from 'worker_threads';
debugger;
parentPort.postMessage({ status: 'Done' });
I'm using Visual Studio Code and I do put breakpoints and event the debugger statement but it never seems to break into the worker file.
The message event does receive the response from the script { status: 'Done' } and the exit event returns 0.
Any ideas on how I can stop at the breakpoint in the worker file entries_worker.js?
Update
Found the following link about how it's not available right now. I'm not 100% sure if it has changed

ndb allow debugger worker thread. run in develop env like this:
"electron-dev": "ndb electron ."
When you use worker thread, you can found it easy:
You can also add breakpoints debug your code:

Related

My spectron app.client doesn't contains all the methods

I'm trying to test my electron app using spectron and mocha, here is my file 'first.js' containing my tests:
const assert = require('assert');
const path = require('path');
const {Application} = require('spectron');
const electronPath = require('electron');
describe('GULP Tests', function () {
this.timeout(30000)
const app = new Application({
path: electronPath,
args: [path.join(__dirname, '..', 'main.js')]
});
//Start the electron app before each test
before(() => {
return app.start();
});
//Stop the electron app after completion of each test
after(() => {
if (app && app.isRunning()) {
return app.stop();
}
});
it('Is window opened', async () => {
const count = await app.client.getWindowCount();
return assert.equal(count, 1);
});
it('Clicks on the project creation button', async () => {
await app.client.waitUntilWindowLoaded();
const title = await app.client.
console.log(title);
return assert.equal(title, 'Welcome to GULP, !');
});
});
My first test is passing, but for the second one i'd like to do a click on an element, but my app.client does not contain a .click methods, and also no getText or getHTML. I've tried to import browser from webdriverio but it was the same problem, I get an error when testing saying me that those methods doesn't exists. I've red the spectron documentation and they're using .click and .getText methods regularly, why I don't get them ? I've imported spectron as it's said in the documentation to.
Thanks.
I have struggled with the same issue for a while. After much trial and error i changed my async methods to normal functions.
it('Clicks on the project creation button', function() {
app.client.waitUntilWindowLoaded();
const title = await app.client.
console.log(title);
return assert.equal(title, 'Welcome to GULP, !');
});
Strange but it worked for me. hopefully it helps.

waitForElement Not JSON Response, when trying to access button element

First of all, I'm quite new to NativeScript and e2e testing, but I'm trying to get some simple tests to run on my demo application. I did the whole setup where I installed everything and an e2e (default) folder + files were created.
I have this demo app layout where I basically have one button:
<ActionBar title="My App" class="action-bar">
</ActionBar>
<GridLayout class="page">
<StackLayout>
<Button automationText="testButton" text="Button"></Button>
</StackLayout>
</GridLayout>
These are my tests:
import { AppiumDriver, createDriver, SearchOptions } from "nativescript-dev-appium";
import { assert } from "chai";
describe("sample scenario", () => {
const defaultWaitTime = 5000;
let driver: AppiumDriver;
before(async () => {
driver = await createDriver();
});
after(async () => {
await driver.quit();
console.log("Quit driver!");
});
afterEach(async function () {
if (this.currentTest.state === "failed") {
// await driver.logTestArtifacts(this.currentTest.title);
}
});
it("should find an element by text", async () => {
const btn = await driver.findElementByText("Button");
assert.isTrue(btn.exists());
});
it("should find an element by automation text", async () => {
const btn = await driver.findElementByAutomationText("testButton");
assert.isTrue(btn.exists());
});
});
I had to comment this line, otherwise, my tests wouldn't finish (I had to manually stop them with ctrl C):
// await driver.logTestArtifacts(this.currentTest.title);
I am running it with:
$ npm build ios
$ npm run e2e -- --runType sim.iPhone6
I am able to run stupid tests, assertTrue(true), but when I am trying to access an element, the button, things go wrong:
should find an element by text:
[waitForElementByXPath("//*[#label='Button' or #value='Button' or #hint='Button']",5000)] [elements("xpath","//*[#label='Button' or #value='Button' or #hint='Button']")] Not JSON response
Error: [elements("xpath","//*[#label='Button' or #value='Button' or #hint='Button']")] Not JSON response
at exports.newError (node_modules/wd/lib/utils.js:151:13)
And:
should find an element by automation text:
[waitForElementByAccessibilityId("testButton",5000)] [elements("accessibility id","testButton")] Not JSON response
Error: [elements("accessibility id","testButton")] Not JSON response
at exports.newError (node_modules/wd/lib/utils.js:151:13)
I also tried to see if the driver was just empty or something like that, but isIOS and isAndroid work fine.
I don't know if this has something do to with it but when killing the driver this error also pops up:
Error: [quit()] Unexpected data in simpleCallback.
If anybody could help that would be great! Thanks!
There seems to be a similar issue logged in at the {N} Appium Github repo, the problem seems to be the environment setup, at least in their case it was not installing carthage.
Did you go through the setup process here, made sure you have everything in place?

Access service worker skipWaiting from within App build with Webpack+Workbox

I have a PWA built with Aurelia and compiled with Webpack, using the Workbox Plugin that generates the sw.js service worker file. I'm trying to make the "New version available" user notification so that the user can activate the new version when clicking on a link within the app.
I am successfully downloading and installing the new version in the background, and even detecting that a new version is ready. However, when I try to call the skipWaiting() method to force refresh of the page with the new version, it fails, because apparently I don't have the right scope or object.
The main problem is probably that I can't edit the actual sw.js because it is automatically generated. The examples all suggest the use of self.skipWaiting();, but I don't know how to access that object.
webpack.config.js
new WorkboxPlugin({
globDirectory: './dist',
globPatterns: ['**/*.{html,js,css,woff,woff2,ttf,svg,eot,jpg}'],
swDest: './dist/sw.js',
clientsClaim: true,
skipWaiting: false, // because I want to notify the user and wait for response
}),
index.ejs
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(reg => {
// make the registration available globally, for access within app
window.myServiceWorkerReg = reg;
// Check for update on loading the app (is this necessary?)
return reg.update();
})
.catch(console.error);
}
</script>
app.js
activate() {
// listener for service worker update
this.swReg = window.myServiceWorkerReg;
console.warn('[app.js] ACTIVATE.', this.swReg);
this.swReg.addEventListener('updatefound', () => {
// updated service worker found in reg.installing!
console.warn('[app.js] UPDATE FOUND.', this.swReg);
const newWorker = this.swReg.installing;
newWorker.addEventListener('statechange', () => {
// has the service worker state changed?
console.warn('[app.js] STATE HAS CHANGED.', newWorker, newWorker.state);
if (newWorker.state === 'installed') {
// New service worker ready.
// Notify user; callback for user request to load new app
myUserMessage({ clickToActivate: () => {
// reload fresh copy (do not cache)
console.warn('[app.js] Post Action: skipWaiting.');
// this.swReg.postMessage({ action: 'skipWaiting' });
// THIS IS THE LINE THAT FAILS
this.swReg.skipWaiting();
}});
}
});
});
}
Everything works fine except the last line (this.swReg.skipWaiting();). Has anyone else used webpack+workbox plugin and gotten the skipWaiting to happen as a result of user interaction?
I finally got it to work. One problem was that I was using an older version of workbox-webpack-plugin. The current version (4.2) includes a listener in the service worker that can trigger self.skipWaiting() when a message is posted to the worker like this:
newWorker.postMessage({ type: 'SKIP_WAITING' });
But you have to ensure that the config has skipWaiting: false; and that you are using the latest version.
These instructions are pretty good:
https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin
https://developers.google.com/web/tools/workbox/guides/advanced-recipes#offer_a_page_reload_for_users
However, I tweaked things to work well between my App and the service worker instantiation in the index.ejs file.
webpack.config.js
new GenerateSW({
globPatterns: ['dist/**/*.{html,js,css,woff,woff2,ttf,svg,eot,jpg}'],
swDest: 'sw.js',
clientsClaim: true,
skipWaiting: false,
})),
index.ejs
<script>
if ('serviceWorker' in navigator) {
// register the service worker
navigator.serviceWorker.register('/sw.js')
.then(reg => {
window.myWorkerReg = reg;
// Check for update on loading the app (is this necessary?)
return reg.update();
})
.catch(console.error);
// The event listener that is fired when the service worker updates
navigator.serviceWorker.addEventListener('controllerchange', function () {
// when the service worker controller is changed, reload the page
if (window.swRefreshing) return;
window.location.reload();
window.swRefreshing = true;
});
}
</script>
app.js
activate() {
// listener for service worker update
this.swReg = window.myWorkerReg;
if (this.swReg) {
// if there is already a new service worker ready to install, prompt user
if (this.swReg.waiting) {
this.promptUpdateServiceWorker(this.swReg.waiting);
}
// add listener to detect when a new service worker is downloaded
this.swReg.addEventListener('updatefound', () => {
// updated service worker is being installed
const newWorker = this.swReg.installing;
// add listener to detect when installation is finished
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed') {
// New service worker ready to activate; prompt user
this.promptUpdateServiceWorker(newWorker);
}
});
});
}
}
// listener for buildVersion
buildVersionChanged(buildVersion) {
// through proprietary code, we've detected a new version could be downloaded now
window.myWorkerReg.update();
}
// New service worker ready. Show the notification
promptUpdateServiceWorker(newWorker) {
// actual code for UI prompt will vary; this is pseudocode
uiPrompt('New_version_ready').then((response) => {
if (response.approved) {
// reload fresh copy (do not cache)
newWorker.postMessage({ type: 'SKIP_WAITING' });
}
});
}
You cannot call it on the page (app.js). You call self.skipWaiting on the Service Worker script (service-worker.js).
https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting

ServiceWorker not receiving fetch requests

I am installing a service worker for the first time, and following the tutorial at: https://developers.google.com/web/fundamentals/getting-started/primers/service-workers
My service worker behaves as expected when installing and updating, but fetch requests are not triggered as expected.
var CACHE_NAME = 'test-cache-v1'
var urlsToCache = [
'/',
'/public/scripts/app.js'
]
self.addEventListener('install', function (event) {
console.log('Installing new service worker', event)
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function (cache) {
return cache.addAll(urlsToCache)
})
.catch(err => console.log('Error Caching', err))
)
})
self.addEventListener('fetch', function (event) {
console.log('Fetch req', event)
event.respondWith(
caches.match(event.request)
.then(function (response) {
console.log('Cache hit', response)
// Cache hit - return response
if (response) {
return response
}
return fetch(event.request)
.catch(e => console.log('Error matching cache', e))
}
)
)
})
I see 'Installing new service worker' outputted to the console when expected, but not 'Fetch req'. I am using Chrome devtools and have accessed the "Inspect" option next to the ServiceWorker under the Application tab.
If you listen for the activate event, and add in a call to clients.claim() inside that event, then your newly active service worker will take control over existing web pages in its scope, including the page that registered it. There's more information in this article on the service worker lifecycle. The following code is sufficient:
self.addEventListener('activate', () => self.clients.claim());
If you don't call clients.claim(), then the service worker will activate, but not control any of the currently open pages. It won't be until you navigate to the next page under its scope (or reload a current page) that the service worker will take control, and start intercepting network requests via its fetch handler.
On dynamic websites, be careful!
If service worker has scope: example.com/weather/
It does not have scope: example.com/weather
Especially on firebase which by default removes trailing slash
In this case, service worker will install, activate, and even cache files, but not receive ‘fetch’ events! Very hard to debug.
Add “trailingSlash”: true to firebase.json under ‘hosting’. This will solve the problem. Make sure to modify rewrite from:
{
"source": "/weather", "function": "weather"
}
To :
{
"source": "/weather/", "function": "weather"
}
As well as manifest.json
I found that Jeff Posnick's "clients.claim()" in the activate event handler was useful, but it was not enough to cache resources the first time the JS app runs. That is because on the first run the service worker has not finished activating when the JS starts loading its resources.
The following function lets the main app register the SW and then waits for it to activate before continuing to load resources:
/**
* Registers service worker and waits until it is activated or failed.
* #param js URI of service worker JS
* #param onReady function to call when service worker is activated or failed
* #param maxWait maximum time to wait in milliseconds
*/
function registerServiceWorkerAndWaitForActivated(js, onReady, maxWait) {
let bReady = false;
function setReady() {
if (!bReady) {
bReady = true;
onReady();
}
}
if ('serviceWorker' in navigator) {
setTimeout(setReady, maxWait || 1000);
navigator.serviceWorker.register(js).then((reg) => {
let serviceWorker = reg.installing || reg.waiting;
if (serviceWorker) {
serviceWorker.addEventListener("statechange", (e) => {
if (serviceWorker.state == "activated")
setReady();
});
} else {
if (!reg.active)
console.log("Unknown service worker state");
setReady();
}
}, () => setReady());
} else {
let msg = "ServiceWorker not available. App will not run offline."
if (document.location.protocol != "https:")
msg = "Please use HTTPS so app can run offline later.";
console.warn(msg);
alert(msg);
setReady();
}
}

ngCordova InAppBrowser plugin freeze app on iOS but no on Android

I am currently using, IONIC v1.0.0, AngularJs and ngCordova v0.1.23-alpha on IOS and Android.
I have come across an issue with my login view freezing up.
It happens after opening InAppBrowser and hitting "back to app" (close button caption used for IOS to get back) is freezes my login view disabling the ability to touch on the whole screen and making me unable to login. It only happens if I call InAppBrowser when starting the app, if I use it during the app life cycle (after login in), it doesn't do it.
Here are some of my code pieces
In app.js:
angular.module('MyApp', ['ionic', 'MyApp', 'ngCordova', 'mainController', 'loginController', 'pascalprecht.translate', 'ngStorage', 'ngSanitize', 'ngAnimate', 'ngTouch', 'ngCookies', 'ngLocale', 'testController'])
In mainController I have Factory:
.factory('customMainFunction', function ($rootScope, $ionicLoading, $ionicScrollDelegate, $ionicPopup,
$timeout, $localStorage, $location, $ionicHistory, $window, $cordovaInAppBrowser) {
var Token = "";
return {
openBrowser: function (link) {
var options = {
location: 'yes',
clearcache: 'yes',
toolbar: 'yes',
closebuttoncaption: 'Back to App'
};
document.addEventListener("deviceready", function () {
$cordovaInAppBrowser.open(link, '_blank', options)
.then(function (event) {
// success
})
.catch(function (event) {
// error
});
}, false);
$rootScope.$on('$cordovaInAppBrowser:loadstart', function (e, event) {
//console.log(event);
var url = "";
var positionNumber;
var res;
url = event.url;
positionNumber = url.search("ssoToken=");
res = url.substr(Number(positionNumber)+9);
/*positionNumber = url.search("module=");
res = url.substr(Number(positionNumber)+6);*/
if(url !== "" && positionNumber >= 0 && res.length > 0) {
$rootScope.$broadcast('ssoToken', { token: res });
$cordovaInAppBrowser.close();
}
});
$rootScope.$on('$cordovaInAppBrowser:loadstop', function (e, event) {
console.log("loadstop");
//console.log(event);
// insert CSS via code / file
//$cordovaInAppBrowser.insertCSS({
// code: ''
//});
// insert Javascript via code / file
//$cordovaInAppBrowser.executeScript({
// file: ''
//});
});
$rootScope.$on('$cordovaInAppBrowser:loaderror', function (e, event) {
});
$rootScope.$on('$cordovaInAppBrowser:exit', function (e, event) {
});
}
}
})
If anybody has encounter such issue please let me know what can be done to resolve it. Any question or clarifications let me know. Thanks in advance.
Found the issue of my own problem. Basically the problem is related to Threading. Look for Threading. How did I find out about it? On XCode I was able to see a message saying:
THREAD WARNING: ['InAppBrowser'] took '108.12' ms. Plugin should use a
background thread
There are two ways to solve this (I believe):
1- Using background threading (just like the message states). Please refer to:
How to run cordova plugins in the background?
2- Wrap the openBrowser function call (in my case) in a setTimeout. That will delay the call until the thread is done and UI won't be blocked. Once done (in my case) it opened the inAppBrowser and when I hit "Back to app" UI was not block at all.
Hope this helps someone out there.

Resources