I'm new on using AVA for JS unit tests and I immediately hit a rock:
My situation is that I want to run a gulp task to run the AVA tests and watch the test files, and in the test file I wrote I need to include the js file that contains the code to test.
The problem is that the file with the code to test is an old js file with all global functions, so needs to be shimmed somehow into an AMD module, but how I can do this without changing the original file?
gulpfile.js
var gulp = require("gulp");
var ava = require("gulp-ava");
var srcUnitTestFiles = ["**/*.tests.js", "!node_modules/*.js"];
gulp.task("unit-tests-exec", () =>
gulp.src(srcUnitTestFiles)
// gulp-ava needs filepaths so you can't have any plugins before it
.pipe(ava({ verbose: true }))
);
gulp.task("unit-tests-watch", () =>
gulp.watch(srcUnitTestFiles, ["unit-tests-exec"])
);
package.json
{
"name": "name",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "ava"
},
"author": "",
"license": "ISC",
"devDependencies": {
"ava": "^0.16.0",
"gulp": "^3.9.1",
"gulp-ava": "^0.14.0",
"jsdom": "^9.4.2"
},
"ava": {
"require": [
"./test/helpers/setup-browser-env.js"
]
}
}
firstTest.tests.js
import test from "ava";
// I need to import the js file to test
test.before(t => {
});
test("foo", t => {
t.pass();
});
test('bar', async t => {
const bar = Promise.resolve('bar');
t.is(await bar, 'bar');
});
Thanks!
I think you mean UMD, not AMD. AMD wouldn't work.
I suggest you follow our recipe on browser testing with jsdom.
You could do the following at the top:
global.document = require('jsdom').jsdom('<body></body>');
global.window = document.defaultView;
require('./your-lib');
And then you can access your library on the window global:
window.yourLib();
With yourLib being the method you attached to window in your library.
Related
I'm trying to use Synpress, but I fail to understand how to solve
TypeError: cy.acceptMetamaskAccess is not a function
Let me share the relevant code* (I mostly followed this tutorial https://medium.com/andamp/how-to-setup-synpress-for-wen3-dapp-frontend-test-automation-with-metamask-73396896684a)
*if something is missing, please let me know
package.json:
{
"devDependencies": {
"#testing-library/cypress": "^8.0.2",
"cypress": "^9.7.0"
},
"scripts": {
"cypress:open": "cypress open",
"test": "env-cmd -f .env npx synpress run -cf synpress.json --config supportFile='tests/support/index.js'",
"test:watch": "env-cmd -f .env npx synpress open -cf synpress.json"
},
"dependencies": {
"#synthetixio/synpress": "^1.2.0",
"env-cmd": "^10.1.0"
}
}
How I configured my synpress.json
{
"baseUrl": "https://dappify.com/",
"userAgent": "synpress",
"retries": { "runMode": 0, "openMode": 0 },
"integrationFolder": "tests/integration",
"screenshotsFolder": "screenshots",
"videosFolder": "videos",
"video": true,
"chromeWebSecurity": true,
"viewportWidth": 1366,
"viewportHeight": 850,
"component": {
"componentFolder": ".",
"testFiles": "**/*spec.{js,jsx,ts,tsx}"
},
"env": {
"coverage": false
},
"defaultCommandTimeout": 30000,
"pageLoadTimeout": 30000,
"requestTimeout": 30000,
"supportFile": "tests/support/index.js"
}
Simple test
describe('Test User Login', () => {
it('Connects with Metamask', () => {
cy.visit('https://dappify.com')
cy.contains('Sign').click();
cy.contains('Confirm').click();
cy.contains('Connect Wallet').click();
cy.contains('Metamask').click();
cy.switchToMetamaskWindow();
cy.acceptMetamaskAccess().should("be.true");
})
})
I don't understand why cy.acceptMetamaskAccess() is not a function, I can find it here: https://github.com/synthetixio/synpress/blob/master/support/index.d.ts
How can I use the functions listed in this index.d.ts file?
** Solution **
Answer by Fody was helpful! Let me summarise the steps needed:
inside support folder you need an index.js
inside index.js
import './commands'
import "#synthetixio/synpress/support";
If you want to add custom functions add this file to support too
inside commands.js:
import "#testing-library/cypress/add-commands";
// here go(es) your custom function(s)
It's a bit hard to untangle the Synpress structure. Usually with a plugin library you import a support component and that adds the library's custom commands to your test.
The article says
Run your tests with env-cmd -f .env npx synpress run -cf synpress.json --config supportFile='support/index.js'
which makes me think the last parameter is bringing in the custom commands.
If you already tried that, the following is the command definition, you can try adding it at the top of your spec.
Cypress.Commands.add('acceptMetamaskAccess', allAccounts => {
return cy.task('acceptMetamaskAccess', allAccounts);
})
I'm building a Nuxt-electron-prisma app and I kinda stuck here. when I use prisma normally as guided every thing is fine on dev but on build i get this error :
A javascript error occurred in the main process
Uncaught exception:
Error: can not find module : '.prisma/client'
I tried changing prisma provider output to ../resources/prisma/client
generator client {
provider = "prisma-client-js"
output = "../resources/prisma/client"
}
and in main.js of electron
const { PrismaClient } = require('../resources/prisma/client');
const prisma = new PrismaClient()
but I get error Cannot find module '_http_common' at webpackMissingModules in both dev and build ! which by others opinion is caused when using prisma on client-side but I only use it on background.js (main.js of the my boilerplate)
I'm using Nuxtron boilerplate for Nuxt-electron which is using yml file for electron-builder config file and in it I also added prisma to files property:
appId: com.example.app
productName: nuxt-electron-prisma
copyright: Copyright © 2021
nsis:
oneClick: false
perMachine: true
allowToChangeInstallationDirectory: true
directories:
output: dist
buildResources: resources
files:
- "resources/prisma/database.db"
- "node_modules/.prisma/**"
- "node_modules/#prisma/client/**"
- from: .
filter:
- package.json
- app
publish: null
and still get errors
in my win-unpacked/resources I have this only: win-unpacked\resources\app.asar.unpacked\node_modules\#prisma\engines
and of course my package.json
{
"private": true,
"name": "nuxt-electron-prisma",
"productName": "nuxt-electron-prisma",
"description": "",
"version": "1.0.0",
"author": "",
"main": "app/background.js",
"scripts": {
"dev": "nuxtron",
"build": "nuxtron build"
},
"dependencies": {
"electron-serve": "^1.0.0",
"electron-store": "^6.0.1",
"#prisma/client": "^3.0.2"
},
"devDependencies": {
"#mdi/font": "^6.1.95",
"#nuxtjs/axios": "^5.13.6",
"#nuxtjs/device": "^2.1.0",
"#nuxtjs/dotenv": "^1.4.1",
"#nuxtjs/vuetify": "1.12.1",
"core-js": "^3.15.1",
"electron": "^10.1.5",
"electron-builder": "^22.9.1",
"glob": "^7.1.7",
"noty": "^3.2.0-beta",
"nuxt": "^2.15.7",
"nuxtron": "^0.3.1",
"sass": "1.32.13",
"swiper": "^5.4.5",
"prisma": "^3.0.2",
"vue-awesome-swiper": "^4.1.1"
}
}
The solution provided by Mojtaba Barari works but it results in #prisma packages being present in both resources/app/node_modules and resources/node_modules.
There is a better way how to do it:
{
"build": {
"extraResources": [
{
"from": "node_modules/.prisma/client/",
"to": "app/node_modules/.prisma/client/"
}
],
}
}
In this case, the Prisma client files will be copied directly to resources/app/node_modules where other #prisma packages are already present and so you will save ~ 10 MB compared to the other solution.
EDIT:
My previous solution doesn't work if an application is packaged into an asar archive. You need to use files field instead:
{
"build": {
"files": [
{
"from": "node_modules/.prisma/client/",
"to": "node_modules/.prisma/client/"
}
],
}
}
This is a universal solution which works even if you don't use an asar archive.
Ok, I finally solved it!!
first of all no need to change client generator output direction!
//schema.prisma
datasource db {
provider = "sqlite"
url = "file:../resources/database.db"
}
generator client {
provider = "prisma-client-js"
// output = "../resources/prisma/client" !! no need for this!
}
then in electron-builder config add ./prisma , #prisma and database
// my config file was a .yml
extraResources:
- "resources/database.db"
- "node_modules/.prisma/**/*"
- "node_modules/#prisma/client/**/*"
// or in js
extraResources:[
"resources/database.db"
"node_modules/.prisma/**/*"
"node_modules/#prisma/client/**/*"
]
this solved `Error: cannot find module : '.prisma/client'
but this alone won't read DB in built exe file!
so in main.js where importing #prisma/client should change DB reading directory:
import { join } from 'path';
const isProd = process.env.NODE_ENV === 'production';
import { PrismaClient } from '#prisma/client';
const prisma = new PrismaClient({
datasources: {
db: {
url: `file:${isProd ? join(process.resourcesPath, 'resources/database.db') : join(__dirname, '../resources/database.db')}`,
},
},
})
with these configs I could fetch data from my sqlite DB
UPDATE: index.js file content added.
I have this electron app that is executing some bash scrips(*.sh) files to perform some task.
Everything is working absolutely fine in the development environment but when building the production build for deb installer for Ubuntu platform, everything is working, like opening on the app, other NodeJS stuff, but bash scripts are not executing.
Problem Statement: How to execute shell scripts in the production build of an electron app for Linux(Ubuntu OS). Getting this error
app/terminal_scripts/timer.sh Not Found
Below are the detailed explanation for the app.
**Project Directory Setup**:
ProjectName
|
app > css | images | js | renders
terminal_scripts
node_modules
package.json
package-lock.json
Where inside the app directory, I have all CSS, images, js, HTML, and terminal scripts.
package.json:
{
"name": "timer",
"productName": "Timely",
"version": "1.0.25",
"description": "This desktop app shows you system clock",
"main": "app/js/main/index.js",
"scripts": {
"start": "electron .",
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "nodemon --exec 'electron .'",
"dist": "electron-builder"
},
"homepage": ".",
"keywords": [
"Electron",
"Desktop App"
],
"author": "NotABot Ltd <contact#notabot.com>",
"contributors": [
{
"name": "Not A Bot",
"email": "nab#notabot.com"
}
],
"license": "ISC",
"dependencies": {
"desandro-matches-selector": "^2.0.2",
"electron-context-menu": "^1.0.0",
"electron-is": "^3.0.0",
"fix-path": "^3.0.0",
"isotope-layout": "^3.0.6",
"jquery": "^3.5.0",
"jquery-bridget": "^2.0.1"
},
"build": {
"appId": "com.test.timely",
"productName": "Timely",
"linux": {
"target": "deb",
"category": "System"
}
},
"devDependencies": {
"electron": "^8.1.1",
"electron-builder": "^22.6.0"
}
}
HTML:
<html>
<head>
<title>Timely</title>
</head>
<body>
<button onclick="displayTime()">Display Time</button>
<textarea rows="20" cols="90" id="command-output" disabled="true"></textarea>
<script>
const {app} = require('electron');
function displayTime(){
console.log("button clicked");
let cmd = `bash app/terminal_scripts/timer.sh`;
let completeMessage = 'This is the message';
backgroundProcess(cmd, completeMessage);
}
function getCommandOutput() { return document.getElementById("command-output"); };
function getStatus() { return document.getElementById("status"); };
function appendOutput(msg) { getCommandOutput().value += (msg+'\n'); };
function setStatus(msg) { getStatus().innerHTML = msg; };
function backgroundProcess(cmd, completeMessage){
const process = require('child_process');
var child = process.execFile(cmd, [] , {shell: true} );
appendOutput("Processing......");
child.on('error', function(err) {
appendOutput('stderr: '+err );
});
child.stdout.on('data', function (data) {
appendOutput(data);
});
child.stderr.on('data', function (data) {
appendOutput(data );
});
return new Promise((resolve, reject) => {
child.on('close', function (code) {
console.log(`code is: ${code}`);
if (code == 0){
setStatus(completeMessage);
resolve(1);
}
else{
setStatus('Exited with error code ' + code);
resolve(-1);
}
});
});
}
</script>
</body>
</html>
Bash Script:
#!/bin/bash
timer="$(date)"
echo "$timer"
Permission is set 777 for this shell file
Platform Information:
OS: Ubuntu 18.04.4 LTS
NodeJS: 13.6.0
NPM: 6.14.5
Electron: 8.1.1
Electron Builder: 22.6.0
index.js
const {app, BrowserWindow, Menu, Tray, ipcMain, MenuItem} = require('electron');
const path = require('path');
const contextMenu = require('electron-context-menu');
let splashWindow;
function createMainWindow(){
mainWindow = new BrowserWindow({
minHeight: 700,
minWidth: 800,
webPreferences: {
nodeIntegration: true,
webviewTag: true
},
show: false
});
//For dev only
// mainWindow.webContents.openDevTools();
mainWindow.loadFile('app/renderer/index.html');
mainWindow.maximize();
}
app.on('ready', () =>{
createMainWindow();
});
Another way is to move flies to a new directory outside app directory and call it as extraResources.
Inside that directory you can add all your bash files and for production you can use below method.
let urlPath = path.join(process.resourcesPath, '/extraResources/')
and then use let cmd = `${urlPath}timer.sh`;
I have created a new directory alongside the app directory called the termainal_scripts.
Inside this, I have my bash file timer.sh.
I figured out how to execute shell scripts, in production by using process.resourcesPath inside path.join().
So, let the fixed path be as:
let fixedURL = path.join(process.resourcesPath, '/terminal_scripts/');
Then the command to execute will be:
let cmd = `${fixedURL}timer.sh`
I'm working with javascript file that has no window or document.
I have package.json file that calls another Javascript file task.js
package.json:
{
"name": "mytask",
"version": "1.0.0",
"description": "mytask TFS Build",
"main": "scripts/mytask.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"install": "npm install"
},
"repository": {},
"author": "OST",
"license": "ISC",
"dependencies": {
"https-proxy-agent": "1.0.0",
"jquery": "3.3.1",
"jsdom": "13.0.0",
"load-json-file": "^2.0.0",
"moment": "^2.22.2",
"object.values": "^1.0.4",
"request": "2.81.0",
"vso-node-api": "^5.1.2",
"vss-web-extension-sdk": "5.141.0",
"vsts-task-lib": "1.1.0"
}
}
TFS call javascript file exist in package.json "main" option.
package.json call mytask.js via "main" option and this javascript file will run as a task in TFS and print things to console.
Basically my issue that there's no HTML page or document so I cannot load javascript file through or document.addElement...
I need to load javascript file (VSS.SDK.js from vss-web-extension-sdk) to mytask.js.
I'm new in javascript so I don't really know what I'm doing wrong.
After long searching, I found "jsdom" which creates a global document. But still didn't know how to load VSS.SDK.js script.
mytask.js:
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const { window } = new JSDOM(`<!DOCTYPE html>`);
var jQuery = require("jquery")(window);
// Option 1
jQuery.loadScript = function (url, callback) {
jQuery.ajax({
url: url,
dataType: 'script',
success: callback,
fail: callback,
async: false
});
}
jQuery.loadScript('vss-web-extension-sdk/lib/VSS.SDK.js', function(){console.log("loaded!!!!!!!!!!!!!!!!!!!!")});
// Option 2
jQuery.getScript('vss-web-extension-sdk/lib/VSS.SDK.js').done(function(){console.log("loaded!!!!!!!!!!!!!")}).fail(function(){console.log("failed!!!!!!!!!!!!!!")});
// Option 3
jQuery.getScript('vss-web-extension-sdk/lib/VSS.SDK.js', function() {
VSS.init({explicitNotifyLoaded: true, usePlatformScripts: true, usePlatformStyles: false});
var serverContext = VSS.getWebContext();
});
I tried these three options but it didn't work! nothing was printed.
I use VSS.SDK to load webContext.
any ideas?
I'm building an app and all works fine while I'm in developer mode. Everythink works as it should. But when I package my app with electron-builder, app opens but it doesnt start express server and app doesnt work properly.
Here is my package.json code
{
"name": "artros",
"version": "1.0.0",
"description": "Artros",
"author": "MC3",
"license": "ISC",
"main": "start.js",
"scripts": {
"pack": "build --dir",
"dist": "build"
},
"build": {
"appId": "com.artros.app",
"productName": "Artros",
"win": {
"target": "portable",
"icon": "build/icon.ico"
},
"mac": {
"target": "dmg"
}
},
"dependencies": {
"body-parser": "^1.18.3",
"ejs": "^2.5.7",
"electron-pdf-window": "^1.0.12",
"express": "^4.16.2",
"multer": "^1.3.0",
"nodemailer": "^4.6.4",
"path": "^0.12.7"
},
"devDependencies": {
"electron": "^1.8.2"
}
}
and here is my start.js code
const cluster = require('cluster');
if (cluster.isMaster) {
require('./main.js'); // your electron main file
cluster.fork();
} else {
require('./app.js'); // your server code
}
and my main.js code
var electron = require('electron');
var browserWindow = electron.BrowserWindow;
var app = electron.app;
app.on('ready', function(){
var appWindow;
//appWindow
appWindow = new browserWindow({
width:1120,
height:620,
webPreferences: {
plugins: true
},
icon: __dirname + '/public/icon/icon.png'
});
appWindow.loadURL('file://' +__dirname + '/public/prva.html');
//appWindow.webContents.openDevTools();
});
// close app after all windows are closed
app.on('window-all-closed', () => {
app.quit()
})
If anybody has any idea what is the problem, please post it. Thanks
I had something similar happen to me. The challenge was that if you use fork() the application path changes. So I would recommend that you check __dirname in all of your files especially the ones in your forked process (e. g. app.js). I wouldn't be surprised if some of them don't make sense anymore.
I found the solution. The problem really was in my app.js code. At one detination I needed to add (path.join(__dirname, './path/to/file')). Guys thanks for your help.