How to allow location when using headless browser of cypress testing on event on click? - geolocation

What I want to do
I want to integrate husky with the Cypress test when trying to commit some changes. So in my package.json file, there are two tests script
"scripts": {
"test:run": "./node_modules/.bin/cypress run",
"test:open": "./node_modules/.bin/cypress open"
},
The test:open is SUCCESS
But The test:run is FAIL
It says that User has not allowed access to system location
This is the function when Button "Godkänn" clicked in "Onboarding" page
const getDevicePermission = async () => {
await getDeviceLocation().then(() =>
getDeviceOrientation().then(() => Router.push(routes.ONBOARDING))
);
};
What I've tried
Add configuration of browser permission in cypress.config.ts
import { defineConfig } from "cypress";
export default defineConfig({
env: {
browserPermissions: {
notifications: "allow",
geolocation: "allow",
},
},
chromeWebSecurity: false,
e2e: {
setupNodeEvents(_on, _config) {
// implement node event listeners here
},
},
});
The result is still FAIL with the same error
I've been following this issue's solution but still got the same error and no typescript support

Add package cypress-browser-permissions
npm i cypress-browser-permissions --save-dev
//or
yarn install cypress-browser-permissions --save-dev
Update your cypress.config.js
const { defineConfig } = require('cypress')
const { cypressBrowserPermissionsPlugin } = require('cypress-browser-permissions')
module.exports = defineConfig({
env: {
browserPermissions: {
notifications: "allow",
geolocation: "allow",
},
},
chromeWebSecurity: false,
e2e: {
setupNodeEvents(on, config) {
config = cypressBrowserPermissionsPlugin(on, config)
return config
},
},
})
Testing
To test, I used an app which essentially does this
navigator.geolocation.getCurrentPosition(showPosition, showError);
With configuration browserPermissions: { geolocation: "ask" } the test throws up a permissions request dialog.
With configuration browserPermissions: { geolocation: "allow" } the test bypasses the dialog and the page displays the lat & long coordinates.
With configuration browserPermissions: { geolocation: "block" } the page shows "User denied the request for Geolocation." and the Cypress log shows the error
(uncaught exception) undefined: User denied Geolocation
App
<html lang="en">
<body>
<div id="demo">Demo</div>
<script>
var demoDiv = document.getElementById("demo");
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition, showError);
}
else { demoDiv.innerHTML = "Geolocation is not supported by this browser."; }
}
function showPosition(position) {
var lat = position.coords.latitude;
var lon = position.coords.longitude;
demoDiv.innerText = `${lat} : ${lon}`
}
function showError(error) {
demoDiv.innerHTML = "User denied the request for Geolocation."
throw error
}
getLocation()
</script>
</body>
</html>

It's because when you are running the tests on the test runner, you are running them on Chrome, And when running it on CLI you are running them on Electron browser. You can add the chrome browser for the run mode.
"test:run": "./node_modules/.bin/cypress run --browser chrome"
To ignore exceptions generated from the application globally, you can add this in cypress/support/e2e.js
Cypress.on('uncaught:exception', (err, runnable) => {
// returning false here prevents Cypress from
// failing the test
return false
})

Related

How to post message from VSCode extension to custom webview created with WebviewProvider?

I am building a VSCode extension where I create a custom tab in the panel with a Webview Provider. I want to direct the output of an extension command to Webview and render in html script. The alternative is to execute vscode extension command inside html script of the webview. However I could not find an example that uses Webview Provider, instead they all have
currentPanel.webview.postMessage({ command: 'refactor' });
which is undefined in my case because I do not create a panel.
extension.js
let disposable = vscode.commands.registerCommand(
"this is where I want to send data to webview"
...
);
var thisProvider={
resolveWebviewView:function(thisWebview, thisWebviewContext, thisToke){
thisWebview.webview.options={enableScripts:true}
thisWebview.webview.html=`<!DOCTYPE html>
<html>
<body>
<div id="results" style="white-space: pre;" />
<script>
const resultsEl = document.getElementById("results");
window.addEventListener('message', event => {
const message = event.data; // The JSON data our extension sent
switch (message.command) {
case 'results':
console.log(results);
break;
}
});
</script>
</body>
</html>`;
}
}
context.subscriptions.push(
vscode.window.registerWebviewViewProvider("monitor.output", thisProvider)
);
package.json:
"contributes": {
"commands": [
{
"command": "monitor.listen",
"title": "Connect"
}
],
"menus": {
"view/title": [
{
"command": "monitor.listen",
"group": "navigation",
"when": "view == monitor.output"
}
]
},
"viewsContainers": {
"panel": [
{
"id": "monitor",
"title": "Monitor",
"icon": "resources/monitor.jpeg"
}
]
},
"views": {
"monitor": [
{
"type": "webview",
"id": "monitor.output",
"name": "Monitor"
}
]
}
}
I was looking for this too, but there is really no example showing how this could be added.
You can get and save the reference to the current webView inside resolveWebView function in your provider.
Store the view in a private instance variable private _view?: vscode.WebviewView; and use it in a public method public postMessageToWebview(message: any)
The provider code:
import * as vscode from 'vscode';
function getNonce() {
let text = "";
const possible =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
export class WebViewProvider
implements vscode.WebviewViewProvider
{
public static readonly viewType = 'myExtension.controlsView';
private _view?: vscode.WebviewView;
constructor(private readonly _extensionUri: vscode.Uri) {
}
public postMessageToWebview(message: any) {
this._view?.webview.postMessage(message);
}
public resolveWebviewView(
webviewView: vscode.WebviewView,
context: vscode.WebviewViewResolveContext,
_token: vscode.CancellationToken,
) {
this._view = webviewView; // needed so we can use it in postMessageToWebview later
webviewView.webview.options = {
// Allow scripts in the webview
enableScripts: true,
localResourceRoots: [this._extensionUri],
};
webviewView.webview.html = this._getHtmlForWebview(
webviewView.webview,
);
webviewView.webview.onDidReceiveMessage((data) => {
switch (data.type) {
// other message types ...
case 'onYourEvent': {
console.log(data.value); // see below webview to extension communication snippet
break;
}
case 'onInfo': {
if (!data.value) {
return;
}
vscode.window.showInformationMessage(data.value);
break;
}
case 'onError': {
if (!data.value) {
return;
}
vscode.window.showErrorMessage(data.value);
break;
}
}
});
}
private _getHtmlForWebview(webview: vscode.Webview) {
// // And the uri we use to load this script in the webview
const scriptUri = webview.asWebviewUri(
vscode.Uri.joinPath(
this._extensionUri,
'out',
'svelte-app/bundle.js',
),
);
// const scriptUri = webview.asWebviewUri(
// vscode.Uri.joinPath(this._extensionUri, "media", "main.js")
// );
// Local path to css styles
const styleResetPath = vscode.Uri.joinPath(
this._extensionUri,
'media',
'reset.css',
);
const stylesPathMainPath = vscode.Uri.joinPath(
this._extensionUri,
'media',
'vscode.css',
);
// Uri to load styles into webview
const stylesResetUri = webview.asWebviewUri(styleResetPath);
const stylesMainUri = webview.asWebviewUri(stylesPathMainPath);
const cssUri = webview.asWebviewUri(
vscode.Uri.joinPath(
this._extensionUri,
'out/svelte-app',
'bundle.css',
),
// vscode.Uri.joinPath(this._extensionUri, "media", "main.css")
);
// Use a nonce to only allow specific scripts to be run
const nonce = getNonce();
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--
Use a content security policy to only allow loading images from https or from our extension directory,
and only allow scripts that have a specific nonce.
-->
<meta http-equiv="Content-Security-Policy" content="img-src https: data:; style-src 'unsafe-inline' ${webview.cspSource}; script-src 'nonce-${nonce}';">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="${stylesResetUri}" rel="stylesheet">
<link href="${stylesMainUri}" rel="stylesheet">
<link href="${cssUri}" rel="stylesheet">
<script nonce="${nonce}">
const tsvscode = acquireVsCodeApi();
</script>
</head>
<body>
</body>
<script nonce="${nonce}" src="${scriptUri}"></script>
</html>`;
}
}
Note:
To get started remove the svelte bundle stuff (this was just part of my code base) and add a script file media/main.js with the code from the webview snippet below.
The CSS files reset.css and vscode.css can be downloaded from a VS Code example
To see your console.log messages you can open your dev. tools in your extension host VS code instance by hitting ctrl+shif+p and type Open webview dev - maybe you have to open/close your webview to generate new console logs.
You can use it in your extension.ts:
import * as vscode from 'vscode';
import { WebViewProvider } from './WebViewProvider';
export function activate(context: vscode.ExtensionContext) {
const provider = new WebViewProvider(context.extensionUri);
context.subscriptions.push(
vscode.commands.registerCommand('myExtension.sayHello', () => {
// The code you place here will be executed every time your command is executed
// Display a message box to the user
// vscode.window.showInformationMessage(output);
provider.postMessageToWebview({
type: 'greeting',
message: 'HelloWorld',
});
}),
);
context.subscriptions.push(
vscode.window.registerWebviewViewProvider(
WebViewProvider.viewType,
provider,
),
);
}
Add it to the package.json so the command & view will be available:
{
"other-config": "...",
"activationEvents": [
"onView:myExtension.controlsView",
"onCommand:myExtension.sayHello"
],
"contributes": {
"views": {
"explorer": [
{
"type": "webview",
"id": "myExtension.controlsView",
"name": "MyExtension"
}
],
},
"commands": [
{
"command": "myExtension.sayHello",
"category": "myExtension",
"title": "SayHello"
},
]
}
}
Webviews can be added at multiple locations in this code it will be added to the explorer view.
Use the following code in your webview script to get the message from the extension:
// main.js code
const handleExtensionMessages = (event) => {
const { message, type }= event.data;
switch (message.type) {
case 'greeting':
console.log("received", message);
break;
}
}
window.addEventListener("message", handleExtensionMessages);
For the other "direction" web view to extension communication.
You can use in your webview content script:
tsvscode.postMessage({
type: "onYourEvent",
value: "anything you like to return",
});
The global tsvscode variable is generated in _getHtmlForWebview with acquireVsCodeApi().
To fix the typing for the global tsvscode. Install #types/vscode-webview with npm as devDependency and add a global.d.ts to your webview script with this content:
import type WebViewApi from '#types/vscode-webview';
global {
declare const tsvscode: WebViewApi<unknown>;
}
Or if you don't like the global variable tsvscode and the typing above. You could also create a VS Code API wrapper like in the following repository.
Just to get this code running, create an extension as mentioned in the Getting Started Guide with Yeoman generator by running yo code in your terminal.
You can also find the snippets in the following Github gist.

My Vue PWA app shows white blank page on iOS

I am currently working one a Vuejs PWA app (using Vue CLI 3). My app works fine on Android, Windows, and macOS, but it only shows a white blank page on ios. More specifically, when I use an iPhone and access my app with Safari or Chrome, it all shows a white page. When I add my app to the home screen of the iPhone, when I open it up, it still shows a white page.
this is link to my app.
White blank screen
I have tried many workarounds here but it not work.
here are some parts of my code:
vue.config.js
module.exports = {
transpileDependencies: ['vuetify'],
pwa: {
workboxPluginMode: 'InjectManifest',
workboxOptions: {
swSrc: 'src/config/firebase-messaging-sw.js',
exclude: [/\.map$/, /_redirects/],
},
manifestOptions: {
start_url: 'index.html',
},
name: 'AppName',
appleMobileWebAppCapable: 'yes',
},
};
router
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "RenterMainView",
component: RenterView,
children: [
{
path: "index.html",
name: "Home",
component: Home,
meta: { guest: true },
alias: ""
},
{
path: "detail/:typeId",
name: "HostelDetail",
component: HostelDetail,
meta: { guest: true }
}
]
}
]
});
router.beforeEach((to, from, next) => {
if (to.matched.some((record) => record.meta.requiresAuth)) {
if (window.$cookies.get('jwt') === null) {
// not logged in
next({
name: 'Login',
params: { nextUrl: to.path, preUrl: from.path },
});
} else {
// logged in
const role = window.$cookies.get('role');
if (to.matched.some((record) => record.meta.is_vendor)) {
if (role === 'vendors') {
next();
} else {
next(from.path);
}
} else if (to.matched.some((record) => record.meta.is_admin)) {
if (role === 'admins') {
next();
} else {
next(from.path);
}
} else if (to.matched.some((record) => record.meta.is_renter)) {
if (role === 'renters') {
next();
} else {
next(from.path);
}
} else {
next();
}
}
} else if (to.matched.some((record) => record.meta.guest)) {
// not require authen
next();
} else {
// not require authen
next();
}
});
Try changing the start_url
I found that on
Chrome Windows
Chrome MacOS
Android
I was OK to use quite a wide variety of start_url values, such as the "index.html" that you have, or "/index.html", etc.
However on iOS, I had to use
start_url: "."
The other values were fine on the other platforms, but gave a blank white screen on iOS.
Try creating a blank PWA with the Vue CLI
Does that work correctly on iOS?
Then step by step change it to contain your app.
Find out where it breaks.
That's how I found the start_url issue.
I hope that this could help someone. In this project, I make an PWA app using Vue, and I use Firebase Cloud Messagging to send notification from server to client. Unfortunaly, due to some restrictions on iOS, FCM doesn't work on it, that is why the application show a white page on iOS. So, the solution is to disable FCM on iOS
if (firebase.messaging.isSupported()) { // your code go here }
using above code to disable FCM on firebase service worker file

electron updater notify for new release but do not update or download new release in windows

electron updater 4.2.0 package do not download new release but can detect it
This is a private repository on github
new releases successfully send to github
In package.json:
"build": {
"appId": "com.myApp.ID",
"npmRebuild": false,
"win": {
"icon": "./resources/electron/icons/256x256.png",
"publish": [
{
"provider": "github",
"owner": "me",
"repo": "POS",
"private": true,
"releaseType": "release",
"token": "<private token>"
}
],
"target": [
{
"target": "nsis",
"arch": [
"x64"
]
}
]
}
},
my electron.js file or main.js I have :
win.webContents.on('did-finish-load', () => {
if(!serve) {
appUpdater(win);
}
});
appUpdater function is:
function appUpdater(win) {
autoUpdater.autoInstallOnAppQuit = true;
autoUpdater.autoDownload = true;
autoUpdater.logger = logger;
/* Log whats happening
TODO send autoUpdater events to renderer so that we could console log it in developer tools
You could alsoe use nslog or other logging to see what's happening */
let foundUpdate = false;
autoUpdater.on('checking-for-update', () => {
dialog.showMessageBox(win, {
message: 'CHECKING FOR UPDATES !!'
});
});
autoUpdater.on('update-available', () => {
foundUpdate = true;
dialog.showMessageBox(win, {
message: ' update-available !!'
});
});
autoUpdater.on('error', error => {
autoUpdater.logger.debug(error);
});
// Ask the user if update is available
autoUpdater.on('update-downloaded', (_event, releaseNotes, _releaseName) => {
let message = 'A new version is now available. It will be installed the next time you restart the application.';
dialog.showMessageBox(win, {
type: 'question',
buttons: ['Install', 'Later'],
defaultId: 0,
message: 'A new version has been downloaded',
detail: message
}, response => {
if(response === 0) {
setTimeout(() => autoUpdater.quitAndInstall(), 1);
}
});
});
// init for updates
setInterval(() => {
if(!foundUpdate) {
autoUpdater.checkForUpdates();
}
}, 60000);
}
exports.appUpdater = appUpdater;
I get documented from auto updater
Auto-updatable Targets is windows nsis
checking-for-update and update-available event fire correctly but update-downloaded or error simply does not fire
Please if you already have experience on this let me know
note: I set environment variable GH_TOKEN in the user machine too
Better now than never
I was struggling with the new update of mac bigSur as electron-builder#^20.38.0 was giving me very bad errors!!!
So I decided to update to the latest version
electron: ^12.0.2
electron-builder: ^22.10.5
electron-updater: ^4.3.8
It was not working at first giving me error like:
Cannot download differentially, fallback to full download: Error: Maximum allowed size is 50 MB.
At last my version of node was v10.15.1 locally
I updated to v14.16.0 now it works!
Another issue using other versions update and downgrade
it was downloading it but failed on install.
Same problem with some specifics versions of electron-builder and electron-updater.For me, it works with exactly:
"electron-builder": "22.11.7"
"electron-updater": "4.3.8"
But for instance, it does not work anymore with electron-updater 4.3.9 ...

Puppeteer Travis-CI chrome-headless not working

I'm trying to automate tests for my students. As a very basic example: write some HTML. So I created a test case to check for an unordered list.
Anyway: It works locally, but it seems I can't get it to work on travis. I might miss a tiny thing, but no idea what's wrong:
https://travis-ci.com/maciossek/hft-asgmt-html-01/jobs/127338669/config
https://github.com/maciossek/hft-asgmt-html-01
Any help highly appreciated!
This is the travis.yml I ended up with (working)
language: node_js
node_js:
- "9"
dist: trusty
sudo: false
addons:
chrome: stable
before_install:
- google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
cache:
yarn: true
directories:
- node_modules
install:
- yarn install
script:
- yarn test
Travis CI updated the sudo-enabled Ubuntu build environments (dist: trusty), so there is no need anymore to install google-chrome-stable.
Here is a complete running example:
.travis.yml
dist: trusty
sudo: required
language: node_js
node_js:
- "8.11.3"
script:
- yarn test
package.json
{
"dependencies": {
"express": "4.16.3"
},
"devDependencies": {
"jasmine": "3.2.0",
"puppeteer": "1.9.0"
},
"main": "src/Server.js",
"name": "example-puppeteer-travis-ci",
"scripts": {
"test": "jasmine"
},
"version": "1.0.0"
}
src/Server.js
const express = require('express');
class Server {
constructor() {
this.app = express();
this.app.get('/', (request, response) => response.send('<title>Hello</title>'));
}
start(port = 8080) {
return new Promise((resolve, reject) => {
if (this.server) {
reject(new Error('Server is already running.'));
} else {
this.server = this.app.listen(port, () => resolve(port));
}
});
}
stop() {
if (this.server) {
this.server.close();
this.server = undefined;
}
}
}
module.exports = Server;
spec/support/ServerSpec.js
const puppeteer = require('puppeteer');
const Server = require('../../src/Server');
describe('Server', () => {
let browser = undefined;
let server = undefined;
beforeEach(async () => {
browser = await puppeteer.launch({args: ['--disable-setuid-sandbox', '--no-sandbox'], dumpio: true});
server = new Server();
});
afterEach(async () => {
if (browser) await browser.close();
if (server) await server.stop();
});
it('serves a homepage with a title', async () => {
const port = await server.start();
const url = `http://localhost:${port}/`;
const page = await browser.newPage();
await page.goto(url);
const title = await page.title();
expect(title).toBe('Hello');
});
});

Getting error while creating Cloud Functions through UI using Inline Editor

I've been using Cloud Functions for quite some time now but recently it is giving me an error while creating it through the UI using Inline Editor. The error that I get is:
Error
The request contains invalid arguments "event_trigger": "projects/my-project-id/buckets/my-bucket-id expected to match template projects/_/buckets/{bucket}"
Tracking Number: **************(some tracking number)
Basically I'm trying to create a function that must get triggered when a file is created/uploaded in a specific GCS bucket that ultimately kicks-off a dataflow job. The function gets deployed when uploaded from local through Cloud SDK Command Line but does not get triggered.
I've created several functions the same way(UI/Command Line) before. Don't know why it is not working now.
The code that I'm using is:
const google = require('googleapis');
exports.jobName = function(event, callback) {
const file = event.data;
if (file.resourceState === 'exists' && file.name) {
console.log(file.name);
console.log(event.data);
google.auth.getApplicationDefault(function (err, authClient, projectId) {
if (err) {
throw err;
}
if (authClient.createScopedRequired && authClient.createScopedRequired()) {
authClient = authClient.createScoped([
'https://www.googleapis.com/auth/cloud-platform',
'https://www.googleapis.com/auth/userinfo.email'
]);
}
const dataflow = google.dataflow({ version: 'v1b3', auth: authClient });
dataflow.projects.templates.create({
projectId: 'project-id',
resource: {
parameters: {
inputFile: `gs://${file.bucket}/${file.name}`,
filename:`${file.name}`
},
jobName: 'cloud-fn',
gcsPath: 'gs://some-bucket/Job'
}
}, function(err, response) {
if (err) {
console.error("problem running dataflow template, error was: ", err);
}
console.log("Dataflow template response: ", response);
callback();
});
});
}
};
Package.json:
{
"name": "something",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"googleapis": "^18.0.0"
}
}

Resources