Openwhisk: Request Entity Too Large - openwhisk

I have a local docker-based setup of Apache Openwhisk (https://github.com/apache/incubator-openwhisk-devtools), and when I'm trying to create an action from of a zip containing a packaged nodejs app with
wsk -i action create test --kind nodejs:6 test.zip -v
I get the following response:
413 Request Entity Too Large
The test.zip is only 5 MB large. What causes this issue? Is there any way to make openwhisk process larger requests?
UPD: the content of the test.zip is generated from a nodejs project, which has only 1 .js, which has a simple kafka topic consumer functionality.
function main(params) {
var kafka = require('kafka-node');
var HighLevelConsumer = kafka.HighLevelConsumer;
var Client = kafka.Client;
if (!(params && params.host)) {
return {error: 'host is required'};
}
if (!(params && params.port)) {
return {error: 'port is required'};
}
if (!(params && params.topic)) {
return {error: 'topic is required'};
}
var host = params.host;
var port = params.port;
var topic = params.topic;
var client = new Client(`${host}:${port}`);
var topics = [{
topic: topic
}];
var options = {
autoCommit: true,
fetchMaxWaitMs: 1000,
fetchMaxBytes: 1024 * 1024,
encoding: 'utf8'
};
var consumer = new HighLevelConsumer(client, topics, options);
consumer.on('message', function(message) {
console.log(message.value);
});
consumer.on('error', function(err) {
console.log('error', err);
});
process.on('SIGINT', function() {
consumer.close(true, function() {
process.exit();
});
});
}
exports.main = main;
And the package.json is the following:
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "test.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node test.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"kafka-node": "^2.6.1"
}
}
It works correctly if I simply run it with npm start.

It looks like the NGINX proxy used to expose the API interface for the OpenWhisk platform defaults to a small value for the maximum request body size.
I have managed to re-produce the issue locally, anything above 512KB returns that error.
I've opened a ticket to see if the default limit can be increased: https://github.com/apache/incubator-openwhisk-devtools/issues/124

Related

Record web browser with sound as a service on linux server with puppeteer

I'm trying to build a service on a linux server to record video a web browser with its sound.
The first step I did with the source code below (using xvfb, puppeteer and ffmpeg) to record successfully.
However when I do a recording with different processes at a same time (different websites) the audio gets mixed up between the processes.
I know this is happening because I used the same default audio output for all processes.
The question is: how can I record the browser with sound that doesn't get mixed up between different processes?
My sample code below:
var Xvfb = require('xvfb');
var puppeteer = require('puppeteer');
const { spawn, spawnSync } = require('child_process');
async function record() {
var xvfb = new Xvfb({
displayNum: 99,
reuse: false,
xvfb_args: [
"-screen", "0", "1920x1080x24",
"-ac",
"-nolisten", "tcp",
"-dpi", "96",
"+extension", "RANDR"
]
});
xvfb.startSync();
var browser = await puppeteer.launch({
headless: false,
defaultViewport: null,
ignoreDefaultArgs: [
"--mute-audio",
"--enable-automation"
],
args: [
"--use-fake-ui-for-media-stream",
"--window-size=1920,1080",
"--start-fullscreen"
]
});
const page = await browser.newPage();
var url = "http://www.noiseaddicts.com/free-samples-mp3/?id=2544";
await page.goto(url);
await page.click('span.map_play');
var time = new Date().getTime();
var options = [
"-video_size", "1920x1080",
"-framerate", "30",
"-f", "x11grab",
"-draw_mouse", "0",
"-i", ":99",
"-f", "pulse",
"-ac", "2",
"-i", "1",
"./output" + time + ".mkv"
];
var cmd = 'ffmpeg';
var proc = spawn(cmd, options);
proc.stdout.on('data', function (data) {
console.log(data);
});
proc.stderr.setEncoding("utf8")
proc.stderr.on('data', function (data) {
console.log(data);
});
proc.on('close', async function () {
console.log('finished');
xvfb.stopSync();
});
}
record();
use puppeteer-stream. and run examples/ffmpeg.js with xfvb-run --auto-servernum node ffmpeg.js you will see the captured output.

Tunneling socket could not be established in Bot Framework Emulator

I have found that I am no longer able to use Bot Framework Emulator on local (not using ngrok, not allowed at my company) after upgrading botbuilder packages to something higher than 4.7 (EDIT: I've now checked and the error appears to be introduced in 4.10. It works fine at version 4.9 and keeping only the botbuilder-testing package at 4.9 doesn't help). Can anyone tell me what has changed that makes this not work, and if there is a way to continue testing locally? This is failing any time I use await context.sendActivity (I'm sure other things don't work as well, but that's as far as I can get). Here is how I set up the bot adapter. AppId and Password are NULL since I am running this locally and not using ngrok.
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId, // this variable is null for local/emulator
appPassword: process.env.MicrosoftAppPassword // this variable is null for local/emulator
});
And here is the full error message. Yes, I know I'm not catching the error but I'm not going to put a try catch block for every sendActivity statement. The error details are no different.
(node:19488) UnhandledPromiseRejectionWarning: Error: BotFrameworkAdapter.processActivity(): 500 ERROR
Error: tunneling socket could not be established, statusCode=403
at new RestError (C:\Users\e0077301\Documents\DevOps Projects\TRaCy nanorep\node_modules\#azure\ms-rest-js\dist\msRest.node.js:1403:28)
at AxiosHttpClient.<anonymous> (C:\Users\e0077301\Documents\DevOps Projects\TRaCy nanorep\node_modules\#azure\ms-rest-js\dist\msRest.node.js:2194:35)
at step (C:\Users\e0077301\Documents\DevOps Projects\TRaCy nanorep\node_modules\tslib\tslib.js:133:27)
at Object.throw (C:\Users\e0077301\Documents\DevOps Projects\TRaCy nanorep\node_modules\tslib\tslib.js:114:57)
at rejected (C:\Users\e0077301\Documents\DevOps Projects\TRaCy nanorep\node_modules\tslib\tslib.js:105:69)
at process._tickCallback (internal/process/next_tick.js:68:7)
at BotFrameworkAdapter.<anonymous> (C:\Users\e0077301\Documents\DevOps Projects\TRaCy nanorep\node_modules\botbuilder\lib\botFrameworkAdapter.js:736:27)
at Generator.throw (<anonymous>)
at rejected (C:\Users\e0077301\Documents\DevOps Projects\TRaCy nanorep\node_modules\botbuilder\lib\botFrameworkAdapter.js:13:65)
at process._tickCallback (internal/process/next_tick.js:68:7)
Here are the full index.js and package.json files:
index.js
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const path = require('path');
const ENV_FILE = path.join(__dirname, '.env');
require('dotenv').config({ path: ENV_FILE });
const request = require('request-promise-native');
// Import and start application insights
const appInsights = require('applicationinsights');
appInsights.setup(process.env.APPINSIGHTS_INSTRUMENTATIONKEY).start();
const appInsightsClient = appInsights.defaultClient;
// Import required packages
const restify = require('restify');
const { CustomLogger } = require('./helpers/CustomLogger');
// Import required bot services. See https://aka.ms/bot-services to learn more about the different parts of a bot.
const { BotFrameworkAdapter, MemoryStorage, ConversationState, UserState, TranscriptLoggerMiddleware } = require('botbuilder');
const { BlobStorage } = require('botbuilder-azure');
// This bot's main dialog.
const { DispatchBot } = require('./bots/dispatchBot');
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about adapters.
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
});
// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
console.error(`\n [onTurnError]: ${ error }`);
// Log to Application Insights
appInsightsClient.trackTrace({
message: `${error.name} - ${path.basename(__filename)}`,
severity: 4,
properties: {'error':error.message,'callStack':error.stack,'botName': process.env.BOTNAME}
});
// Send a message to the user
await context.sendActivity(`Sorry, I've encountered an unexpected error and I had to cancel our last activity. If you continue to receive this error, please contact your support team.`);
// Clear out state
await conversationState.delete(context);
};
if (process.env.BOTNAME == 'Bot_Local') {
// Memory storage - for development only
console.log(`\nUsing MemoryStorage for state storage`);
const memoryStorage = new MemoryStorage();
var conversationState = new ConversationState(memoryStorage);
var userState = new UserState(memoryStorage);
} else {
// Blob storage - for production
console.log(`\nUsing BlobStorage for state storage`);
const blobStorage = new BlobStorage({
containerName: 'bot-storage',
storageAccountOrConnectionString: process.env.blobStorageServiceName,
storageAccessKey: process.env.blobStorageAccessKey
});
var conversationState = new ConversationState(blobStorage);
var userState = new UserState(blobStorage);
}
// Set up transcript logger
const transcriptLogger = new TranscriptLoggerMiddleware(new CustomLogger(appInsightsClient));
adapter.use(transcriptLogger);
// Pass in a logger to the bot.
//const logger = console;
const logger = appInsightsClient;
// Create the main dialog
let bot = new DispatchBot(conversationState, userState, logger);
// Create HTTP server
let server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function() {
console.log(`\n${ server.name } listening to ${ server.url }`);
console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
console.log(`\nSee https://aka.ms/connect-to-bot for more information`);
});
const restifyBodyParser = require('restify').plugins.bodyParser;
server.use(restifyBodyParser());
// Listen for incoming activities and route them to your bot main dialog.
server.post('/api/messages', (req, res) => {
// Route received a request to adapter for processing
adapter.processActivity(req, res, async (turnContext) => {
// route to bot activity handler.
await bot.run(turnContext);
});
});
// Respond to pings
server.get('/api/ping', (req, res) => {
res.send('Ping acknowledged');
});
// Listen for incoming notifications and send proactive messages to users.
server.post('/api/notify', async (req, res) => {
console.log(req.body);
try {
const conversationReference = req.body.conversationReference;
await adapter.continueConversation(conversationReference, async turnContext => {
// If you encounter permission-related errors when sending this message, see
// https://aka.ms/BotTrustServiceUrl
await turnContext.sendActivity(req.body.message);
});
res.setHeader('Content-Type', 'text/html');
res.writeHead(200);
res.write('<html><body><h1>Proactive messages have been sent.</h1></body></html>');
res.end();
} catch (error) {
console.log('Bad request');
appInsightsClient.trackTrace({
message: `${error.name} - ${path.basename(__filename)} /api/notify`,
severity: 4,
properties: {'error':error.message,'callStack':error.stack,'botName': process.env.BOTNAME}
});
res.setHeader('Content-Type', 'text/html');
res.writeHead(400);
res.write('<html><body><h1>Bad Request. Please ensure your message contains the conversation reference and message text.</h1></body></html>');
res.end();
}
});
server.post('/directline/token', async (req, res) => {
try {
var body = {User:{Id:req.body.userId}};
const response = await request({
url: 'https://directline.botframework.com/v3/directline/tokens/generate',
method: 'POST',
headers: { Authorization: `Bearer ${process.env.DIRECTLINE_SECRET}`},
json: body,
rejectUnauthorized: false
});
const token = response.token;
res.setHeader('Content-Type', 'text/plain');
res.writeHead(200);
res.write(token);
res.end();
} catch(err) {
console.log(err);
res.setHeader('Content-Type', 'text/plain');
res.writeHead(500);
res.write('Call to retrieve token from Direct Line failed');
res.end();
}
})
package.json (with botbuilder packages updated to latest. If I downgrade all of them to 4.7.0 it works)
{
"name": "core-bot",
"version": "1.0.0",
"description": "A bot that demonstrates core AI capabilities",
"author": "Microsoft",
"license": "MIT",
"main": "index.js",
"nyc": {
"exclude": [
"test",
"helpers/cardHelper.js"
]
},
"scripts": {
"start": "node ./index.js",
"watch": "nodemon ./index.js",
"lint": "eslint .",
"test:dev": "mocha test/**/*test.js",
"test": "nyc --reporter=text --reporter=cobertura mocha test/**/*test.js --timeout 10000 --reporter mocha-multi-reporters --reporter-options configFile=./mocha-reporter-config.json",
"test:inspect": "mocha test/**/*test.js --inspect-brk",
"testList": "node ./node_modules/mocha-list-tests/mocha-list-tests.js test/"
},
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/BotBuilder-Samples.git"
},
"dependencies": {
"#microsoft/recognizers-text-data-types-timex-expression": "^1.1.4",
"#sendgrid/mail": "^6.4.0",
"applicationinsights": "^1.6.0",
"azure-storage": "^2.10.3",
"botbuilder": "^4.12.0",
"botbuilder-ai": "^4.12.0",
"botbuilder-azure": "^4.12.0",
"botbuilder-dialogs": "^4.12.0",
"botbuilder-testing": "^4.12.0",
"crypto": "^1.0.1",
"dotenv": "^6.1.0",
"mocha": "^6.2.2",
"mocha-list-tests": "^1.0.2",
"nock": "^11.7.0",
"remove-markdown": "^0.3.0",
"restify": "^7.2.3",
"turndown": "^5.0.3",
"xml2js": "^0.4.22"
},
"devDependencies": {
"eslint": "^5.16.0",
"eslint-config-standard": "^12.0.0",
"eslint-plugin-import": "^2.19.1",
"eslint-plugin-node": "^8.0.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"https-proxy-agent": "^5.0.0",
"mocha-junit-reporter": "^1.23.1",
"mocha-multi-reporters": "^1.1.7",
"nodemon": "^1.19.4",
"nyc": "^14.1.1",
"source-map-support": "^0.5.16"
}
}
If you are on windows machine, try setting this system environment variable – NODE_TLS_REJECT_UNAUTHORIZED=0 instead of HTTPS_PROXY. This resolves emulator localhost issue running on http protocol to start communicating with the services that are on https. The proxy setting no longer works with botbuilder packages 4.10 and greater.

Spectron test leaves window open

I am using just the basic Spectron test file (in Typescript) to open my app, get the window count, and presumably exit. However, Spectron's app.stop() only seems to close the dev tools window and leaves the main window running. I've searched around and come across a few GitHub issues with people having this problem. The best people seem to offer is to use pkill. I don't want to do that as it could potentially kill more than it should (on a CI server, for example).
Before I show all the code, my question is, what do I need to do to make Spectron's session actually exit after a test?
Here's my spec.ts containing my tests:
import { Application } from "spectron";
import * as assert from "assert";
import * as electronPath from "electron";
import * as path from "path";
describe('Application launch', function () {
this.timeout(10000);
beforeEach(function () {
this.app = new Application({
path: electronPath,
args: [path.join(__dirname, '..')]
} as any);
return this.app.start();
})
afterEach(function () {
if (this.app && this.app.isRunning()) {
// TODO: figure out way to close all windows
return this.app.electron.app.quit();
}
});
it('shows an initial window', function () {
return this.app.client.getWindowCount().then(function (count: any) {
//assert.equal(count, 1)
// Please note that getWindowCount() will return 2 if `dev tools` are opened.
assert.equal(count, 2);
});
});
});
Here's my package.json:
{
"main": "dist/js/entry/main.js",
"scripts": {
"build": "node_modules/.bin/tsc -p tsconfig.json && mkdir -p dist/static && rsync -ar --delete static/ dist/static/",
"lint": "node_modules/.bin/tslint -c tslint.json -p tsconfig.json",
"start": "node_modules/.bin/electron .",
"build_start": "npm run build && npm start",
"package": "node_modules/.bin/electron-builder",
"package-test": "node_modules/.bin/electron-builder --dir",
"test": "node_modules/.bin/mocha -r ts-node/register -r ignore-styles -r jsdom-global/register test/*.ts"
},
"devDependencies": {
"#types/chai": "^4.1.4",
"#types/mocha": "^5.2.4",
"ajv": "^6.5.1",
"asar": "^0.14.3",
"chai": "^4.1.2",
"electron": "^2.0.3",
"electron-builder": "^20.16.0",
"ignore-styles": "^5.0.1",
"jasmine": "^3.1.0",
"jsdom": "^11.11.0",
"jsdom-global": "^3.0.2",
"mocha": "^5.2.0",
"spectron": "^3.8.0",
"ts-node": "^7.0.0",
"tslint": "^5.10.0",
"typescript": "^2.9.2"
},
"build": {
"appId": "your.id",
"files": [
"dist/**/*"
],
"directories": {
"output": "build"
},
"linux": {
"category": "Video",
"target": [
"deb",
"snap"
]
}
},
"dependencies": {
"#types/core-js": "^2.5.0",
"moment": "^2.22.2",
"winston": "^3.0.0"
}
}
Here's my main.ts:
import { app, BrowserWindow, ipcMain, crashReporter } from "electron";
import * as path from "path";
process.env.ELECTRON_PROCESS_NAME = "main";
import { initLogger } from "../common/logging";
let log = initLogger();
log.info("=== Starting up ===");
let mainWindow: Electron.BrowserWindow = null;
function createMainWindow() {
if (mainWindow === null) {
mainWindow = new BrowserWindow({
height: 600,
width: 800,
});
mainWindow.loadFile(path.join(__dirname, "../../static/ui.html"));
mainWindow.webContents.openDevTools();
}
}
app.on("ready", createMainWindow);
app.on("window-all-closed", () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== "darwin") {
log.info("Exiting...");
app.quit();
}
});
app.on("activate", () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
createMainWindow();
});
A simple solution is to disable devtools because they wont be in your final version anyway. You could add a "--debug" argument (parsed in main.js) and add it to the "start" script in package.json. Then, the devtools wont open in your test if you don't add the argument.
If you want to keep devtools or just be sure to exit your app, you can stop your main process with the Node.js exit() function which is a bit brutal:
afterEach(function () {
if (this.app && this.app.isRunning()) {
this.app.mainProcess.exit(0);
}
});
I choose to have a mix of both disabling devtools and be sure to exit (to prevent any bug in my app that could prevent to exit). I'm not familiar with Mocha beceause I use AVA instead and I work in JS instead of TS. So I tried to adapt this code but there may be some mistakes:
beforeEach(function () {
this.app = new Application({
path: electronPath,
// you could add --debug in the following array
// don't do it, to keep the devtools closed
args: [path.join(__dirname, '..')]
} as any);
return this.app.start();
})
// use ES8 'async' to be able to wait
afterEach(async function () {
if (this.app && this.app.isRunning()) {
// get the main process PID
let pid = this.app.mainProcess.pid;
// close the renderer window using its own js context
// to get closer to the user action of closing the app
// you could also use .stop() here
await this.app.client.execute(() => {
window.close();
});
// here, the app should be close
try {
// check if PID is running using '0' signal (throw error if not)
process.kill(pid, 0);
}
catch(e) {
// error catched : the process was not running
// do someting to end the test with success !
return;
}
// no error, process is still running, stop it
this.app.mainProcess.exit(1);
// do someting to end the test with error
return
}
});
Try this
app.on('window-all-closed', () => {
// prevent quit on MacOS. But also quit if we are in test.
if (process.platform !== 'darwin' || isTest) {
app.quit();
}
});
And isTest is const isTest = process.env.NODE_ENV === 'test';
Then the app will properly quit!
To get process.env.NODE_ENV, you may need to update your webpack to use DefinePlugin:
new webpack.DefinePlugin({
'process.env.NODE_ENV': `"${process.env.NODE_ENV ?? 'production'}"`,
// global: {},
}),
With latest Electron, you have to open your Window with contextIsolation set to false.
const win = new BrowserWindow({
...,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true
}
})

How to get nightwatch test_workers work with browserstack-local

I am trying to get Nightwatch's inbuilt parallel test_workers working with browserstack-local for local url testing.
When running tests without browserstack local, Nightwatch test_workers seem to work just fine. The same is true for running local tests without test_workers enabled.
I have tried the examples found here https://github.com/browserstack/nightwatch-browserstack but none of these uses browserstack-local in combination with Nightwatch test_workers.
When running locally with test_workers I get the following output.
Connecting local
Connected. Now testing...
Process terminated with code 0.
Has anyone else encountered similar issues?
EDIT: I have since resolved this issue and have posted an answer below
I have dumped the relevant configuration files below.
My local.conf.js
nightwatch_config = {
globals_path: 'globals.js',
output_folder: false,
src_folders: ['tests'],
selenium: {
'start_process': false,
'host': 'hub-cloud.browserstack.com',
'port': 80
},
test_workers: {
"enabled": true,
"workers":2
},
test_settings: {
default: {
desiredCapabilities: {
'browserstack.user': process.env.BROWSERSTACK_USER,
'browserstack.key': process.env.BROWSERSTACK_ACCESS_KEY,
'browserstack.local': true,
'browserstack.debug': false,
}
}
}
};
// Code to copy seleniumhost/port into test settings
for (let i in nightwatch_config.test_settings) {
if (nightwatch_config.test_settings.hasOwnProperty(i)) {
let config = nightwatch_config.test_settings[i];
config['selenium_host'] = nightwatch_config.selenium.host;
config['selenium_port'] = nightwatch_config.selenium.port;
}
}
module.exports = nightwatch_config;
local.runner.js
#!/usr/bin/env node
var Nightwatch = require('nightwatch');
var browserstack = require('browserstack-local');
var bs_local;
process.env.BROWSERSTACK_ID = new Date().getTime();
try {
process.mainModule.filename = "./node_modules/.bin/nightwatch";
// Code to start browserstack local before start of test
console.log("Connecting local");
Nightwatch.bs_local = bs_local = new browserstack.Local();
bs_local.start({ 'key': process.env.BROWSERSTACK_ACCESS_KEY }, function (error) {
if (error) throw error;
console.log('Connected. Now testing...');
Nightwatch.cli(function (argv) {
Nightwatch.CliRunner(argv)
.setup(null, function () {
// Code to stop browserstack local after end of parallel test
bs_local.stop(function () { });
})
.runTests(function () {
// Code to stop browserstack local after end of single test
bs_local.stop(function () { });
});
});
});
} catch (ex) {
console.log('There was an error while starting the test runner:\n\n');
process.stderr.write(ex.stack + '\n');
process.exit(2);
}
and my package.json script
node ./local.runner.js -c ./local.conf.js
The issue here was due to the module filename being incorrectly defined in the local.runner.js
process.mainModule.filename = "./node_modules/.bin/nightwatch";
should be pointed directly at the Nightwatch file in its directory.
process.mainModule.filename = "./node_modules/nightwatch/bin/nightwatch";
The difference in these files and the exact reason for this solution working are beyond me.
The answer was derived from the "suite" runner in https://github.com/browserstack/nightwatch-browserstack
It seems you are not specifying browsers. Modify your configuration file to be inline with the following configuration file:
var browserstack = require('browserstack-local');
nightwatch_config = {
src_folders : [ "local" ],
selenium : {
"start_process" : false,
"host" : "hub-cloud.browserstack.com",
"port" : 80
},
test_workers: {
"enabled": true,
"workers":2
},
common_capabilities: {
'browserstack.user': process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME',
'browserstack.key': process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY',
'browserstack.debug': true,
'browserstack.local': true
},
test_settings: {
default: {},
chrome: {
desiredCapabilities: {
browser: "chrome"
}
},
firefox: {
desiredCapabilities: {
browser: "firefox"
}
},
safari: {
desiredCapabilities: {
browser: "safari"
}
}
}
};
// Code to support common capabilites
for(var i in nightwatch_config.test_settings){
var config = nightwatch_config.test_settings[i];
config['selenium_host'] = nightwatch_config.selenium.host;
config['selenium_port'] = nightwatch_config.selenium.port;
config['desiredCapabilities'] = config['desiredCapabilities'] || {};
for(var j in nightwatch_config.common_capabilities){
config['desiredCapabilities'][j] = config['desiredCapabilities'][j] || nightwatch_config.common_capabilities[j];
}
}
module.exports = nightwatch_config;

Microsoft Edge issue on export HTML to PDF in ASP.NET Core

I am trying to generate pdf from Html on an ASP.Net Core Web project. I haven't found much on web regarding this. Most of the packages are not ready for asp.net core. After browsing for days, I found this How to export HTML to PDF in ASP.NET Core
I have downloaded the project
Export to pdf works perfectly on chrome but not on Edge; It just never finished the export.
Is there any issue with Edge and pdf I haven't do much work on node.js so not sure what is going wrong. Any help will be highly appreciated. Here, I also add the code from pdf.js
module.exports = function (callback, html) {
var jsreport = require('jsreport-core')();
jsreport.init().then(function () {
return jsreport.render({
template: {
content: html,
engine: 'jsrender',
recipe: 'phantom-pdf'
}
}).then(function (resp) {
callback(null, resp.content.toJSON().data);
});
}).catch(function (e) {
callback(e, null);
})
};
And the package.json for nodejs
{
"name": "pdf",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"jsreport-core": "^1.3.1",
"jsreport-phantom-pdf": "^1.4.4",
"jsreport-jsrender": "^1.0.2"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Updated
#Martin Beeby find the issue on Controller code. The following code is not working on MS Edge
public class HomeController : Controller
{
[HttpGet]
public async Task<IActionResult> Index([FromServices] INodeServices nodeServices)
{
HttpClient hc = new HttpClient();
var htmlContent = await hc.GetStringAsync($"http://{Request.Host}/report.html");
var result = await nodeServices.InvokeAsync<byte[]>("./pdf", htmlContent);
HttpContext.Response.ContentType = "application/pdf";
HttpContext.Response.Headers.Add("x-filename", "report.pdf");
HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "x-filename");
HttpContext.Response.Body.Write(result, 0, result.Length);
return new ContentResult();
}
}
If you change the controller code to:
public async Task<IActionResult> Index([FromServices] INodeServices nodeServices)
{
HttpClient hc = new HttpClient();
var htmlContent = await hc.GetStringAsync($"http://{Request.Host}/report.html");
var result = await nodeServices.InvokeAsync<byte[]>("./pdf", htmlContent);
return File(result, "application/pdf", "report.pdf");
}
Then it works in Chrome and prompts to Download in Edge.

Resources