Jest can not deal with insertAdjacentElement? - jestjs

I want to test a quite simple JS function
export function displaySpinner() {
const loadingOverlayDOM = document.createElement('DIV');
const spinner = document.createElement('IMG');
loadingOverlayDOM.id = 'overlay-spinner';
loadingOverlayDOM.className = 'content-overlay';
spinner.className = 'is-spinning';
spinner.setAttribute('src', '/assets/img/svg/icons/spinner.svg');
l loadingOverlayDOM.insertAdjacentElement('beforeend', spinner);
document.body.insertAdjacentElement('beforeend', loadingOverlayDOM);
}
with this (for the purpose of this issue stripped down) Jest test code:
test('displaySpinner displays the spinner overlay in the current page', () => {
utils.displaySpinner();
});
But the test run yells at me:
FAIL app/helper/utils.test.js
● utils › displaySpinner displays the spinner overlay in the current page
TypeError: loadingOverlayDOM.insertAdjacentElement is not a function
at Object.displaySpinner (app/helper/utils.js:185:439)
at Object.<anonymous> (app/helper/utils.test.js:87:15)
at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
at process._tickCallback (internal/process/next_tick.js:109:7)
Is this an error in Jest or am I missing something here?

I finally found the answer myself:
Jest uses jsdom which does not yet support the DOM function insertAdjacentElement (see this issue on GitHub and it's references). So I'll have to wait until jsdom implements it or use another method in my JS.
You can replace the default version of jsdom with an up-to-date version (e.g. 14) by installing the corresponding module:
npm install --save-dev jest-environment-jsdom-fourteen
or using yarn:
yarn add jest-environment-jsdom-fourteen --dev
and then using the jest testEnvironment config parameter:
{
"testEnvironment": "jest-environment-jsdom-fourteen"
}
Note that if you launch jest with the --env=jsdom argument, this will override the config file, so you need to remove it.

Related

How to mock electron when running jest with #kayahr/jest-electron-runner

Setup
I want to unit test my electron app with jest. For this I have the following setup:
I use jest and use #kayahr/jest-electron-runner to run it with electron instead of node. Additionally, since it is a typescript project, I use ts-jest.
My jest.config.js looks like this:
module.exports = {
collectCoverage: true,
coverageDirectory: 'coverage',
coverageProvider: 'v8',
preset: 'ts-jest',
runner: '#kayahr/jest-electron-runner/main',
testEnvironment: 'node',
};
The test is expected to run in the main process. I have reduced my code to the following example function:
import { app } from 'electron';
export function bar() {
console.log('in bar', app); //this is undefined when mocked, but I have a real module if not mocked
const baz = app.getAppPath();
return baz;
}
The test file:
import electron1 from 'electron';
import { bar } from '../src/main/foo';
console.log('in test', electron1); //this is undefined in the test file after import
// jest.mock('electron1'); -> this does just nothing, still undefined
const electron = require('electron');
console.log('in test after require', electron); //I have something here yay
jest.mock('electron'); //-> but if I comment this in -> it is {} but no mock at all
it('should mock app', () => {
bar();
expect(electron.app).toBeCalled();
});
What do I want to do?
I want to mock electron.app with jest to look whether it was called or not.
What is the problem?
Mocking electron does not work. In contrast to other modules like fs-extra where jest.mock() behaves as expected.
I don't understand the behavior happening here:
Importing "electron" via import in the file containing the tests (not the file to be tested!) does not work (other modules work well), but require("electron") does.
I do have the electron module if not mocked in bar(), but after mocking not
while jest.mock("fs-extra") works, after jest.mock("electron") electron is only an empty object, not a mock
I would really like to understand what I did wrong or what the problem is. Switching back to #jest-runner/electron does not seem to be an option, since it is not maintained anymore. Also I don't know if this is even the root of the problem.
Has anyone seen this behavior before and can give me a hint where to start searching?

nodemon starting `node server.js` TypeError: marked is not a function

I'm creating a blog, using this 'Web Dev Simplified' tutorial:
https://www.youtube.com/watch?v=1NrHkjlWVhM
I've copied the code from git hub https://github.com/WebDevSimplified/Markdown-Blog, installed the node modules and linked it to my mongodb database online.
Node Modules include;
express, mongoose, ejs, --save-dev nodemon, slugify, method-override, dompurify, jsdom.
The database was working and I could save articles, until I added the last part about sanitizing HTML and converting markdown to HTML, this is when the 'TypeError: marked is not a function' comes up, and the save button ceases to work.
Seems a once understood function is now not understood because of a more recent node module dependency, either the dompurify library or jsdom. I'm really out of my depth here! please help!
From Marked Documentation:
https://marked.js.org/#demo
Node JS
import { marked } from 'marked';
// or const { marked } = require('marked');
const html = marked.parse('# Marked in Node.js\n\nRendered by **marked**.');
Your Code:
if (this.markdown) {
this.sanitizedHtml = dompurify.sanitize(marked(this.markdown))
}
try this:
if (this.markdown) {
this.sanitizedHtml = dompurify.sanitize(marked.parse(this.markdown))
}
its work for me
In my case:
const { marked } = require('marked');
instead of
const marked = require('marked')
...
this.sanitizedHTML = dompurify.sanitize(marked.parse(this.markdown))
Per node example documentation at https://marked.js.org/#demo

Redux-Observable breaks on server-side rendering

I have a test repo with redux-observable
It works with webpack-dev-server but breaks with server-side-rendering giving:
TypeError: action$.ofType(...).delay is not a function
How to reproduce:
yarn dev works okay (webpack-dev-server).
yarn build && yarn start - runs node server-side-rendering which is breaking when creating store with redux createStore method.
It recognizes imported operators from rxjs within a browser (webpack-dev-server). My guess it might be a problem with webpack serverConfig, more specifically with:
externals: fs.readdirSync('./node_modules').concat([
'react-dom/server',
]).reduce((ext, mod) => {
ext[mod] = `commonjs ${mod}`;
return ext;
}, {}),
importing the whole rxjs library will jeopardise your tree shaking.
use pipe instead.
import { delay } from 'rxjs/operators';
const epic = action$ => action$
.ofType('baz')
.pipe(delay(5000))
.mapTo({ type: 'bar' });
;
It turned out I had to include rxjs in server.js where express is like:
import `rxjs`;
But I would swear I tried that solution before I posting a question.

Accessing filesystem in Angular 2 app using Electron

I know that Angular 2 is run on a web browser, which does not have access to the file system.
However, I'm using Electron as my front-end, and also running the app via electron:
"build-electron": "ng build --base-href . && cp src/electron/* dist",
"electron": "npm run build-electron && electron dist"
Therefore, I run it with npm run electron which at the very end runs electron dist.
Since I'm running through electron and not ng I would think that I should be able to access the filesystem. However, when I do:
import * as fs from 'fs'
I get an error:
ng:///AppModule/AppComponent_Host.ngfactory.js:5 ERROR TypeError: __WEBPACK_IMPORTED_MODULE_0_fs__.readFileSync is not a function(…)
Similarly, when I try: var fs = require('fs');
I get:
ng:///AppModule/AppComponent_Host.ngfactory.js:5 ERROR TypeError: fs.readFileSync is not a function
This is the call resulting in the error:
this.config = ini.parse(fs.readFileSync('../../CONFIG.ini', 'utf-8'))
Does anyone have any idea what's causing this?
Thanks.
Solved it by:
1) Eject webpack: ng eject
2) Add target: 'electron-renderer' to the module.exports array inside webpack.config.js
3) Require remote, since we're in the renderer, but fs is only available in the main process (Read more): var remote = require('electron').remote;
4) Require fs (this time using remotes implementation of require): var fs = remote.require('fs');
And now it works!
I am using
Angular CLI: 7.0.7
Node: 8.12.0
OS: win32 x64
Angular: 7.0.4
I tried the ng eject method it didn't work in my case, it is disabled by default and will be removed completely in Angular 8.0
Error message: The 'eject' command has been disabled and will be removed completely in 8.0.
It worked for me by creating a file called native.js in the src folder and insert the following:
`window.fs = require('fs');
Add this file to the angular-cli.json scripts array:
"scripts": [
"native.js"
]
Add the following lines to polyfills.ts:
`declare global {
interface Window {
fs: any;
}
}`
After that you can access the filesystem with:
`window.fs.writeFileSync('sample.txt', 'my data');`
credits
As I understand it, you build the application with Webpack.
You can expose all Node modules via the externals array in your webpack config.
module.exports = {
"externals": {
"electron": "require('electron')",
"child_process": "require('child_process')",
"fs": "require('fs')",
"path": "require('path')",
...
}
}
Since they are provided through the Webpack externals, one does not have to require them but use them with imports.
import * as fs from 'fs'
You can read more about this problem in my article.
I'm late to the party but I also stumbled upon this problem recently. To the late comers, you can use ngx-fs
https://github.com/Inoverse/ngx-fs
Usage:
const fs = this._fsService.fs as any;
fs.readdir("\\", function (err, items) {
if (err) {
return;
}
for (let i = 0; i < items.length; i++) {
console.log(items[i]);
}
});
I had the same problem and could solve it in an easier way:
Just download this project as start, the 'require'-s are already in the webpack.config.js file (along with the integration of angular, electron and so on):
https://github.com/maximegris/angular-electron
import 'fs' into home.ts (or into any other component) as mentioned by #Matthias Sommer above:
import * as fs from 'fs'
Use 'fs' :)

Not able to load AMD modules through Jest

I'm trying to use Jest for unit testing my React code but I'm also using requirejs and so all my React code is in AMD modules. It obviously works well in browser but when I run Jest tests, it can't load my AMD modules.
Initially it was giving me error for define saying define is not defined, so I used amdefine by Requirejs to fix it. Now it can understand define but still can't load my module.
I had the same problem today and here is what I've done :
Module.js
(()=> {
const dependencies = ['./dep.js'];
const libEnv = function (dep) {
// lib content
function theAnswer (){
return dep.answer;
}
return {theAnswer}; // exports
};
//AMD & CommonJS compatibility stuff
// CommonJS
if (typeof module !== 'undefined' && typeof require !== 'undefined'){
module.exports = libEnv.apply(this, dependencies.map(require));
module.exports.mockable = libEnv; // module loader with mockable dependencies
}
// AMD
if (typeof define !== 'undefined') define(dependencies, libEnv);
})();
You will found all needed files on my github repository to test :
in browser for requirejs
with node for jest
https://github.com/1twitif/testRequireJSAmdModulesWithJest
I ran into same problem, so I went ahead and mocked my dependency at the top of test file:
jest.mock('../../components/my-button', () => {
// mock implementation
})
import MyButton from '../../components/my-button';
This way, when MyButton is loaded, its dependency is already mocked, so it won't try to load the RequireJS module.
There's no official Facebook support for requirejs in Jest yet. But's planned. Look this thread:
https://github.com/facebook/jest/issues/17
Also in this thread Sterpe posted a plugin he wrote to do it (but I didn't try it):
https://github.com/sterpe/jest-requirejs

Resources