Adding additional spec files to an angular project, not loading/defining correctly? - node.js

Caveat: I am not the author of this project. Whoever originally wrote this is no longer with the organization and I am seemingly the most knowledgeable on this topic at this point.
I know a little about javascript and unit tests, so I successfully added one .spec.js file. I tried adding a second one for another module, reusing a lot of the spec setup, and it immediately broke.
Project resources:
Nodejs 12.16.1
jasmine-node-karma: "^1.6.1"
karma: "^6.3.12"
Contents of ./karma.conf.js:
module.exports = function(config) {
config.set({
basePath: './public',
frameworks: ['jasmine', 'jquery-3.2.1'],
files: [
"../node_modules/angular/angular.js",
"../node_modules/angular-mocks/angular-mocks.js",
"../node_modules/bootstrap/dist/js/bootstrap.js",
"../public/**/*.js",
],
exclude: [
],
preprocessors: {
},
client: {
captureConsole: true
},
browserConsoleLogOptions: {
terminal: true,
level: ""
},
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['FirefoxHeadless', 'ChromeHeadlessNoSandbox', 'PhantomJS'],
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
},
FirefoxHeadless: {
base: 'Firefox',
flags: ['-headless'],
}
},
singleRun: false,
concurrency: Infinity
})
}
Originally I added ./public/controllers.spec.js to match the existing ./public/controllers.js. These unit tests pass and continue to do so.
Yesterday I added ./public/backups/backupcontrollers.spec.js to match ./public/backups/backupcontrollers.js.
Contents of ./public/backups/backupcontrollers.js:
/**
* Angular controller.
*/
'use strict'
const backupApp = angular.module('backup', [])
const backupTypePath = 'elasticsearch'
backupApp.controller('BackupFormController', ['$scope', '$filter', '$http', function ($scope, $filter, $http) {
console.log('Started BackupFormController')
$scope.itemInstances = []
$scope.fetchStatus = 'Ready!'
$scope.processSelection = function (item, backupType = backupTypePath) {
$scope.currentItem = item.metadata.name
$scope.getBackup(backupType)
console.log('currentItem after selecting from dropdown: ' + $scope.currentItem)
}
$scope.init = function (backupType = backupTypePath) {
$scope.refreshItemInstances(backupType)
console.log('currentItem after loading page for first time: ' + $scope.currentItem)
}
$scope.getBackup = function (backupType = backupTypePath) {
const path = `/v1/backup/${backupType}`
$scope.fetchStatus = `Fetching Backups for Item ${$scope.currentItem}...`
console.log(`Fetching backups for item from ${path}`)
$http.get('/api', { headers: { path: path, item: $scope.currentItem } })
.success(function (data, status, headers, config) {
console.log(`Got data from GET on path ${path}, HTTP status ${status}: ${JSON.stringify(data)}`)
if (typeof data === 'string' || data instanceof String) {
$scope.backups = data.split(/\r?\n/)
} else {
$scope.backups = data
}
$scope.fetchStatus = 'Ready!'
console.log('Done fetching backup list for item:' + $scope.currentItem + '!')
})
.error(function (data, status, header, config) {
console.log(data)
$scope.fetchStatus = 'Ready!'
})
}
// Refresh the list of displayed Item instances
$scope.refreshItemInstances = function (backupType = backupTypePath) {
console.log('Fetching list of all items in the system ...')
$scope.fetchStatus = 'Fetching Items ... '
$http.get('/env')
.success(function (data, status, headers, config) {
console.log(data)
for (let i = 0; i < data.length; i++) {
$scope.itemInstances.push(data[i])
}
$scope.currentItem = $scope.itemInstances[0].metadata.name
console.log('Done fetching list of all items!')
console.log('currentItem after fetching list of all items: ' + $scope.currentItem)
$scope.fetchStatus = 'Ready!'
$scope.getBackup(backupType)
})
.error(function (data, status, header, config) {
console.log(data)
$scope.fetchStatus = 'Ready!'
})
}
}])
Contents of ./public/backups/backupcontrollers.spec.js:
describe('BackupFormController', function () {
let $controller, $rootScope, $httpBackend
beforeEach(module('backup'))
const mockBackupString = 'string of backup data'
const mockBackupData = {
body: mockBackupString
}
const mockItemsUnsorted = [
{
metadata: {
name: 'prod-mock-1',
spec: 'asdf',
status: 'ok'
},
notes: []
},
{
metadata: {
name: 'dev-mock-1',
spec: 'asdf',
status: 'ok'
},
notes: []
},
{
metadata: {
name: 'integ-mock-1',
spec: 'asdf',
status: 'ok'
},
notes: []
}
]
beforeEach(inject(function ($injector) {
$rootScope = $injector.get('$rootScope')
const $controller = $injector.get('$controller')
$httpBackend = $injector.get('$httpBackend')
const mockEnv = $httpBackend.when('GET', '/env')
.respond(mockItemsUnsorted)
const mockAPI = $httpBackend.when('GET', '/api')
.respond(mockBackupString)
const createController = function () {
return $controller('BackupFormController', { '$scope': $rootScope })
}
}))
describe('$scope.getBackup', function () {
beforeEach(function () {
spyOn(console, 'log')
})
it('should GET /api and set $scope.backups', function () {
controller = createController()
console.log('Dumping fetchStatus: ', $rootScope.fetchStatus)
$rootScope.init()
$httpBackend.flush()
expect($rootScope.backups).toEqual(mockBackupString)
expect(console.log).toHaveBeenCalled()
})
})
})
It seems like this new spec isn't working correctly at all; when I run npm test I see the normal successful tests from ./public/controllers.spec.js but also:
Chrome Headless 105.0.5195.125 (Mac OS 10.15.7) BackupFormController $scope.getBackup should GET /api and set $scope.backups FAILED
ReferenceError: createController is not defined
at UserContext.<anonymous> (backup/backupcontrollers.spec.js:51:7)
at <Jasmine>
This is the only output concerning ./public/backups/backupcontrollers.spec.js.
Has anybody run into this before? I found some posts regarding including angular-mocks, but as you can see in karma.conf.js, it's being included.

Related

How to setup Avo App with Google Analytics 4?

right now I am setting up Avo to send events tracking to Google Analytics 4 and feeling a bit confused about the process.
I have managed to send events to Avo, but nothing goes to GA4. I include a photo of how I set up the GA4 Destination for more info. Can anyone help me?
I am quite new with GA4 as well, so there might be some problems with setting up GA4 as well.
const initAvoApp = async () => {
console.log('running')
const env = () => {
if (process.env.NODE_ENV === 'development') return { inspector: Inspector.AvoInspectorEnv.Dev, avoEnv: AvoEnv.Dev }
if (process.env.NEXT_APP_ENV === 'staging')
return { inspector: Inspector.AvoInspectorEnv.Staging, avoEnv: AvoEnv.Dev }
return { inspector: Inspector.AvoInspectorEnv.Prod, avoEnv: AvoEnv.Prod }
}
const inspector = new Inspector.AvoInspector({
apiKey: 'nbhQNPWSaF9SHA1w1jhk',
env: env().inspector,
version: '1.0.0',
appName: 'My App',
})
const customDestination = {
logEvent: function (eventName: string, eventProperties: object) {
window.gtag('event', eventName, eventProperties)
},
identify: function (userId: string) {
// Todo: Identify user in Google Analytics
window.gtag('event', 'identity', userId)
},
unidentify: function () {
// Todo: Unidentify currently identified user in Google Analytics
window.gtag('event', 'identity', null)
},
revenue: function (amount: number, eventProperties: object) {
window.gtag('event', 'purchase', { ...eventProperties, amount })
},
logPage: function (screenName: string, eventProperties: object) {
window.gtag('event', 'screen_view', {
...eventProperties,
screen_name: screenName,
})
},
}
!!customDestination &&
initAvo(
{
env: env().avoEnv,
inspector: inspector,
reportFailureAs: 'log',
},
[customDestination],
customDestination,
)
}
Destination Setup

Vite keeps refreshing the entire page

I migrated from CRA to Vite and it keeps refreshing the entire page.
I saw this issue #7131 on GitHub and that's not my problem.
Here's my vite.config.js:
import { defineConfig, loadEnv } from 'vite'
import react from '#vitejs/plugin-react'
const path = require(`path`)
const aliases = {
'#Form': 'src/Components/Form/Exports',
'#List': 'src/Components/List/Exports',
'#Browse': 'src/Components/Browse/Browse',
'#Tree': 'src/Components/Tree/Exports',
'#Tab': 'src/Components/Tab/Exports',
'#Dashboard': 'src/Components/Dashboard/Dashboard',
'#Panel': 'src/Panel/Panel',
}
const resolvedAliases = Object.fromEntries(
Object.entries(aliases).map(([key, value]) => [key, path.resolve(__dirname, value)]),
)
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, '.')
console.log(env)
const htmlPlugin = () => {
return {
name: "html-transform",
transformIndexHtml(html) {
return html.replace(/%(.*?)%/g, function (match, p1) {
return env[p1]
})
},
}
}
return {
resolve: {
alias: resolvedAliases
},
plugins: [react(), htmlPlugin()],
server: {
host: '0.0.0.0',
hmr: {
clientPort: 443
}
}
}
})
Since my project contains hundreds of components, and it use OAuth and third party authenticators, each reload takes a considerable amount of time (maybe 5 seconds).
This hugely slows down the development.
What should I do to fix this?
What should I do to prevent this?

How to make kuzzle-device-manager plugin API actions works?

I successfully installed and loaded kuzzle-device-manager in the backend file:
import { Backend } from 'kuzzle';
import { DeviceManagerPlugin } from 'kuzzle-device-manager';
const app = new Backend('playground');
console.log(app.config);
const deviceManager = new DeviceManagerPlugin();
const mappings = {
updatedAt: { type: 'date' },
payloadUuid: { type: 'keyword' },
value: { type: 'float' }
}
deviceManager.devices.registerMeasure('humidity', mappings)
app.plugin.use(deviceManager)
app.start()
.then(async () => {
// Interact with Kuzzle API to create a new index if it does not already exist
console.log(' started!');
})
.catch(console.error);
But when i try to use controllers from that plugin for example device-manager/device with create action i get an error output.
Here is my "client" code in js:
const { Kuzzle, WebSocket } = require("kuzzle-sdk")
const kuzzle = new Kuzzle(
new WebSocket('KUZZLE_IP')
)
kuzzle.on('networkError', error => {
console.error('Network Error: ', error);
})
const run = async () => {
try {
// Connects to the Kuzzle server
await kuzzle.connect();
// Creates an index
const result = await kuzzle.query({
index: "nyc-open-data",
controller: "device-manager/device",
action: "create",
body: {
model: "model-1234",
reference: "reference-1234"
}
}, {
queuable: false
})
console.log(result)
} catch (error) {
console.error(error.message);
} finally {
kuzzle.disconnect();
}
};
run();
And the result log:
API action "device-manager/device":"create" not found
Note: The nyc-open-data index exists and is empty.
We apologize for this mistake in the documentation, the device-manager/device:create method is not available because the plugin is using auto-provisioning until the v2.
You should send a payload to your decoder, the plugin will automatically provision the device if it does not exists https://docs.kuzzle.io/official-plugins/device-manager/1/guides/decoders/#receive-payloads

How to create electron auto updates using private github repository?

The update is being detected but I'm unable to download it to my app.
I get the following error:
Status: Update Available
Status: Error in auto-updater. Error: Cannot download "https://api.github.com/repos/[username]/[repo-name]/releases/assets/15151663", status 404: Not Found.
The problem appears only using private github repository not public!!
I've tried installing auto updates to a clean electron react-boilerplate and it works perfectly fine with private github repository.. So i'm a bit at a loss what to do here..
I did some research and it seems like app-update.yml should contain github token (electron-builder should generate it) but my app-update.yml (which is located in release/win-unpacked/resources) does not contain a token...
It only contains this info:
owner: [username]
repo: [repo-name]
provider: github
updaterCacheDirName: [appname]
How can I generate it?
Other comment states that I should have a separate release-only repository which I do, but it still doesn't work.
Electron Autoupdater with Private GitHub Repository?
Other people say that downgrading versions fix this problem, but I also saw people say that doesn't fix it and downgrading isn't really a good option.
My steps of adding gh-token:
I setup my github info in package.json (this token is being ignored)
"publish": {
"provider": "github",
"owner": "[username]",
"repo": "[repo-name]",
"token": "[gh-token]",
"private": true
}
"repository": {
"type": "git",
"url": "https://github.com/[username]/[repo-name].git"
},
So I add it to my main.js aswell just in case.
autoUpdater.setFeedURL({
provider: 'github',
repo: '[repo-name]',
owner: '[username]',
private: true,
token: '[gh-token]'
});
process.env.GH_TOKEN = "[gh-token]";
When I remove setFeedURL I get the exact same error as in this questions:
https://github.com/electron-userland/electron-builder/issues/2641
latest.yml (generated file in github releases along side installer.exe installer.exe.blockmap and installer.msi)
version: [version-number]
files:
- url: [app-name.exe]
sha512: [string]
size: [file-size]
path: [app-name.exe]
sha512: [string]
releaseDate: [release-date]
versions i'm using:
"electron": "^3.0.10",
"electron-builder": "^20.38.4",
"electron-updater": "^4.0.0",
full main.js
import { app, BrowserWindow, ipcMain, dialog } from 'electron';
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import MenuBuilder from './menu';
export default class AppUpdater {
constructor() {
log.transports.file.level = 'info';
autoUpdater.logger = log;
autoUpdater.checkForUpdatesAndNotify();
}
}
let mainWindow = null;
autoUpdater.setFeedURL({
provider: 'github',
repo: '[repo-name]',
owner: '[username]',
private: true,
token: '[gh-token]'
});
process.env.GH_TOKEN = "[gh-token]";
if (process.env.NODE_ENV === 'production') {
const sourceMapSupport = require('source-map-support');
sourceMapSupport.install();
}
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
require('electron-debug')();
}
const installExtensions = async () => {
const installer = require('electron-devtools-installer');
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
return Promise.all(
extensions.map(name => installer.default(installer[name], forceDownload))
).catch(console.log);
};
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
const sendStatusToWindow = (text) => {
log.info(text);
if(mainWindow){
mainWindow.webContents.send('message', text);
}
}
autoUpdater.on('checking-for-update', () => {
sendStatusToWindow('Checking for update...');
});
autoUpdater.on('update-available', (info) => {
sendStatusToWindow('Update available.');
dialog.showMessageBox({
message: 'update available !!'
});
});
autoUpdater.on('update-not-available', (info) => {
sendStatusToWindow('Update not available.');
});
autoUpdater.on('error', (err) => {
sendStatusToWindow('Error in auto-updater. ' + err);
});
autoUpdater.on('download-progress', (progressObj) => {
let log_message = "Download speed: " + progressObj.bytesPerSecond;
log_message = log_message + ' - Downloaded ' + progressObj.percent + '%';
log_message = log_message + ' (' + progressObj.transferred + "/" + progressObj.total + ')';
sendStatusToWindow(log_message);
})
autoUpdater.on('update-downloaded', (info) => {
sendStatusToWindow('Update downloaded');
dialog.showMessageBox({
message: 'Update downloaded, restarting app..'
});
autoUpdater.quitAndInstall();
});
app.on('ready', async () => {
autoUpdater.checkForUpdatesAndNotify();
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
await installExtensions();
}
mainWindow = new BrowserWindow({
show: false,
width: 1024,
height: 728
});
mainWindow.webContents.openDevTools();
mainWindow.loadURL(`file://${__dirname}/app.html`);
mainWindow.webContents.on('did-finish-load', () => {
if (!mainWindow) {
throw new Error('"mainWindow" is not defined');
}
if (process.env.START_MINIMIZED) {
mainWindow.minimize();
} else {
mainWindow.show();
mainWindow.focus();
}
});
mainWindow.on('closed', () => {
mainWindow = null;
});
const menuBuilder = new MenuBuilder(mainWindow);
menuBuilder.buildMenu();
new AppUpdater();
});
I package my app using:
"package": "yarn build && electron-builder build --publish never"
And then I publish it to github releases using:
"gh-publish": "electron-builder --x64 -p always"
import {autoUpdater} from 'electron-updater';
autoUpdater.setFeedURL({
provider: 'github',
owner: 'your_username',
repo: 'your_repo_name',
private: true,
token: process.env.GH_TOKEN, // provide your github access token, with repo:access
});
For the reference to pulling the update, look into this repo:
https://github.com/iffy/electron-updater-example

Cannot set property '__UglifyJsPlugin' of undefined

I am using the following plugin to paralelized the uglify step in webpack
https://github.com/tradingview/webpack-uglify-parallel
unfortunately, I get the following error:
Fatal error: Cannot set property '__UglifyJsPlugin' of undefined
Here's my webpack config:
/*jslint node: true */
var webpack = require("webpack"),
_ = require("lodash"),
path = require("path"),
fs = require("fs"),
os = require('os'),
UglifyJsParallelPlugin = require('webpack-uglify-parallel'),
webpackConfig,
commonsPlugin = new webpack.optimize.CommonsChunkPlugin('m-common-[chunkhash:8].js'),
dedupePlugin = new webpack.optimize.DedupePlugin(),
uglifyPlugin = new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
parallelUglify = new UglifyJsParallelPlugin({
workers: os.cpus().length
}),
sourceMapPlugin = new webpack.SourceMapDevToolPlugin('[file].map', null,
'[absolute-resource-path]',
'[absolute-resource-path]'),
fnCaseSensitivityPlugin = function () {
this.plugin('normal-module-factory', function(nmf) {
nmf.plugin('after-resolve', function(data, done) {
var parentDir = path.dirname(data.resource);
var resourceName = path.basename(data.resource);
fs.readdir(parentDir, function(err, files) {
if (err) {
done(err);
}
if (files.indexOf(resourceName) === -1) {
var realName = _.find(files, function(filename) {
return filename.toLowerCase() === resourceName.toLowerCase();
});
done(new Error('CaseSensitivityPlugin: `' + resourceName + '` does not match the corresponding file on disk `' + realName + '`'));
return;
}
done(null, data);
});
});
});
},
fnDonePlugin = function () {
this.plugin("done", function(stats) {
var statsByChunk = JSON.parse(JSON.stringify(stats.toJson())).assetsByChunkName;
webpackConfig.statsByChunk = statsByChunk;
for (var chunkName in statsByChunk) {
if (statsByChunk.hasOwnProperty(chunkName)) {
var nameIn = statsByChunk[chunkName][0],
gzName = nameIn.substring(0, nameIn.length - 2) + "gz.js";
webpackConfig.filesToCompress['./marvel-web/dist/' + gzName] = './marvel-web/dist/' + nameIn;
// The mrvlBuildOut object contains a set of name/value
// pairs to be used during HTML template processing.
// There are certain filenames we need to add to the
// mrvlBuildOut object as properties so that they can be
// injected into HTML templates that make use of them.
// The code below takes the nameIn string which will have
// one of 2 forms:
//
// Debug Builds:
// m-core-fixed.js
//
// Produciton Builds:
// m-core-<chunkid>.js
//
// It strips off everything after the last dash including the
// .js extension so we are left with the base filename. We then
// use that filename base to look up the name of the property
// we should set to that filename on the mrvlBuildOut object.
var map = webpackConfig.mrvlBuildOutFilePropMap,
propName = map[nameIn.replace(/-[^-]+\.js$/ , '')];
if (propName) {
webpackConfig.mrvlBuildOut[propName] = nameIn;
}
}
}
webpackConfig.webpackDoneListeners.forEach(function (fnCall) {
fnCall(statsByChunk);
});
});
};
webpackConfig = {
mrvlBuildOut: {
//gets filled in with m-common-[chunkhash] and m-web-[chunkhash]
},
mrvlBuildOutFilePropMap: {
"m-common": "marvelcommon",
"m-web": "marvelweb",
"m-blog": "marvelblog",
"m-gallery": "marvelgallery",
"m-landing": "marvellanding",
"m-unsupported": "marvelunsupported",
"m-login": "marvellogin",
"m-voice-chrome": "voicechrome",
"m-apps-chrome": "appschrome",
"m-viewpage-chrome": "viewpagechrome"
},
webpackDoneListeners: [],
filesToCompress: {
},
marvel: {
addVendor: function (name, path, noparse) {
this.resolve.alias[name] = path;
if (noparse) {
this.module.noParse.push(new RegExp(path));
}
this.entry.vendors.push(name);
},
addBuildOutFilePropMapEntry: function( filenameBase, propName ) {
if ( filenameBase && propName ) {
webpackConfig.mrvlBuildOutFilePropMap[filenameBase] = propName;
}
},
stats: {
colors: true,
modules: true,
reasons: false
},
entry: {
'm-web': './marvel-web/js/app.js',
'm-blog': './marvel-web/js/app-blog.js',
'm-gallery': './marvel-web/js/app-gallery.js',
'm-landing': './marvel-web/js/app-landing.js',
'm-unsupported': './marvel-web/js/app-unsupported.js',
'm-login': './marvel-web/js/app-login.js',
'm-voice-chrome': './marvel-web/js/app-voice-chrome.js',
'm-apps-chrome': './marvel-web/js/app-apps-chrome.js',
'm-viewpage-chrome': './marvel-web/js/app-viewpage-chrome.js',
vendors: []
},
resolve: {
modulesDirectories: [
'node_modules',
'marvel-web',
'marvel-web/js'
],
alias: {
// If you find yourself wanting to add an alias here, think
// about if it would be better for your component to live in
// marvel-core instead of in marvel-web. See the README.md in
// marvel-core for more info.
'marvel-apps': __dirname + '/marvel-web/js/apps.js',
'uuid': 'node-uuid'
}
},
output: {
path: 'marvel-web/dist',
filename: '[name]-[chunkhash:8].js',
chunkFilename: '[name]-[chunkhash:8].js'
},
module: {
noParse: [
/[\/\\].html$/
]
},
plugins: [
commonsPlugin,
dedupePlugin,
parallelUglify,
fnCaseSensitivityPlugin,
sourceMapPlugin,
fnDonePlugin
]
}
};
var libs_dir = __dirname + '/marvel-core/src/js/lib/';
webpackConfig.marvel.addVendor("jquery", libs_dir + "jQuery/jquery.min.js", true);
webpackConfig.marvel.addVendor("lodash", libs_dir + "lodash/lodash.min.js", true);
webpackConfig.marvel.addVendor("underscore", libs_dir + "lodash/lodash.min.js", true);
webpackConfig.marvel.addVendor("q", libs_dir + "q/q.js", true);
webpackConfig.marvel.addVendor("backbone", libs_dir + "backbone/backbone-min.js", false);//if we don't parse backbone then require is not found??
webpackConfig.marvel.addVendor("cookie", libs_dir + "cookie/cookie.js", true);
webpackConfig.marvel.addVendor("canvas-to-blob", libs_dir + "canvas-to-blob/canvas-to-blob.js", true);
webpackConfig.marvelDebug = {
watch: true,
keepAlive: true,
stats: webpackConfig.marvel.stats,
entry: webpackConfig.marvel.entry,
resolve: webpackConfig.marvel.resolve,
output: {
path: 'marvel-web/dist',
filename: '[name]-fixed.js',
chunkFilename: '[name]-fixed.js'
},
module: webpackConfig.marvel.module,
//devtool: "eval-source-map",
devtool: "source-map",
//devtool: "eval",
addBuildOutFilePropMapEntry: webpackConfig.marvel.addBuildOutFilePropMapEntry,
plugins: [
commonsPlugin,
dedupePlugin,
fnCaseSensitivityPlugin,
sourceMapPlugin,
fnDonePlugin
]
};
webpackConfig.marvelDebug.output.pathinfo = true;
module.exports = webpackConfig;
The plugin works in my project when I don't include a separate entry for the original UglifyJsPlugin. Try removing that and add its config to the UglifyJsParallelPlugin.

Resources