When c8yDataModule is added, expections are occuring in the angular6 Applications - cumulocity

I know that c8yDataModule is in beta, but still i can use it. I used this c8yDataModule in one app, but it is not working in another app, and i get a lot of errors.
I have imported the C8yDataModule in my angular6 application like this below and then in the imports & exports i have added it.
import { C8yDataModule } from '#c8y/ngx-data';
The error is saying about the corss-fetch and some more errors. So i also raised a ticket in cross-fetch and the authors says to check the latest version of the corss-fetch.
Apart from this many other errors are also coming, so i request you to check these errors and guide us.
https://github.com/lquixada/cross-fetch/issues/22
ERROR in node_modules/#c8y/ngx-data/node_modules/#c8y/client/lib/src/core/FetchClient.d.ts(1,29): error TS7016: Could not find a declaration file for module 'cross-fetch'. 'C:/Projects/angular-its-code/node_modules/cross-fetch/dist/node-ponyfill.js' implicitly has an 'any' type.
Try `npm install #types/cross-fetch` if it exists or add a new declaration (.d.ts) file containing `declare module 'cross-fetch';`
node_modules/#c8y/ngx-data/node_modules/#c8y/client/lib/src/core/IAuthentication.d.ts(10,5): error TS2411: Property 'tenant' of type 'string | undefined' is not assignable to string index type 'string'.
node_modules/#c8y/ngx-data/node_modules/#c8y/client/lib/src/core/IAuthentication.d.ts(11,5): error TS2411: Property 'user' of type 'string | undefined' is not assignable to string index type 'string'.
node_modules/#c8y/ngx-data/node_modules/#c8y/client/lib/src/core/IAuthentication.d.ts(12,5): error TS2411: Property 'password' of type 'string | undefined' is not assignable to string index type 'string'.
node_modules/#c8y/ngx-data/node_modules/#c8y/client/lib/src/core/IAuthentication.d.ts(13,5): error TS2411: Property 'token' of type 'string | undefined' is not assignable to string index type 'string'.
node_modules/#c8y/ngx-data/node_modules/#c8y/client/lib/src/core/IAuthentication.d.ts(14,5): error TS2411: Property 'tfa' of type 'string | undefined' is not assignable to string index type 'string'.
node_modules/#c8y/ngx-data/node_modules/rxjs/internal/symbol/observable.d.ts(4,9): error TS2687: All declarations of 'observable' must have identical modifiers.
Thanks
BA
{
"name": "frontend",
"version": "4.0.0",
"license": "MIT",
"browserslist": [
"dead"
],
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"#angular/animations": "^6.1.0",
"#angular/common": "^6.1.0",
"#angular/compiler": "^6.1.0",
"#angular/core": "^6.1.0",
"#angular/forms": "^6.1.0",
"#angular/http": "^6.1.0",
"#angular/platform-browser": "^6.1.0",
"#angular/platform-browser-dynamic": "^6.1.0",
"#angular/router": "^6.1.0",
"#c8y/ngx-components": "0.0.2-beta2",
"core-js": "^2.5.4",
"rxjs": "^6.0.0",
"rxjs-compat": "6.2.2",
"zone.js": "~0.8.26"
},
"devDependencies": {
"#angular-devkit/build-angular": "~0.6.8",
"#angular/compiler-cli": "^6.1.7",
"#angular/language-service": "^6.1.7",
"#angular/platform-browser": "^6.1.0",
"#c8y/ngx-components": "0.0.2-beta1",
"#types/jasmine": "^2.8.8",
"#types/jasminewd2": "~2.0.2",
"#types/node": "^10.9.4",
"angular-translate": "^2.18.1",
"codelyzer": "^4.4.4",
"jasmine-core": "~2.8.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "^2.0.5",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "^1.4.3",
"karma-jasmine": "^1.1.2",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.2",
"ts-node": "^7.0.1",
"tslint": "~5.9.1",
"typescript": "^2.9.2"
}
}
// angular core
import {NgModule, ErrorHandler} from '#angular/core';
import {BrowserModule} from '#angular/platform-browser';
import {FormsModule} from '#angular/forms';
import {HttpClientModule, HttpClient, HTTP_INTERCEPTORS} from '#angular/common/http';
import {TranslateModule, TranslateLoader} from '#ngx-translate/core';
// app modules / services / constants / ...
import {AppComponent} from './app.component';
import {AppRoutingModule} from './app.routing';
import {AlertComponent} from './shared/components/alert.component';
import {AuthGuard} from './core/auth/auth.guard';
import {JwtInterceptor} from './core/http/jwt.interceptor';
import {CatchErrorInterceptor} from "./core/http/catch-error.interceptor";
import {AlertService} from './shared/services/alert.service';
import {AuthenticationService} from './shared/services/authentication.service';
import {InlineEditService} from "./shared/services/inline-edit.service";
import {UserService} from './shared/services/user.service';
import {SideNavService} from "./layouts/main-layout/services/side-nav.service";
import {LoginModule} from './modules/login/login.module';
import {createTemparTranslateLoader} from "./core/i18n/tempar-translation-loader";
import { CumulocityService } from '../app/shared/services/c8y.service';
import { C8yDataModule } from '#c8y/ngx-data';
export class UIErrorHandler extends ErrorHandler {
constructor() {
super();
}
handleError(error: any) {
super.handleError(error);
alert(`Error occurred:${error.message}`);
}
}
#NgModule({
declarations: [
AppComponent,
AlertComponent,
],
imports: [
// core
BrowserModule,
FormsModule,
HttpClientModule,
// routing
AppRoutingModule,
// app
LoginModule,
C8yDataModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: createTemparTranslateLoader,
deps: [HttpClient]
}
})
],
providers: [
AuthGuard,
AlertService,
AuthenticationService,
SideNavService,
UserService,
InlineEditService,
CumulocityService,
// {
// provide: ErrorHandler,
// useClass: UIErrorHandler
// },
{
provide: HTTP_INTERCEPTORS,
useClass: JwtInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: CatchErrorInterceptor,
multi: true
}
],
bootstrap: [
AppComponent,
],
exports: [
C8yDataModule
]
})
export class AppModule {
}
authentication.service.ts.
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { environment } from '../../../environments/environment';
import { User } from "../../models/user";
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { CumulocityService } from './c8y.service';
#Injectable()
export class AuthenticationService {
loggedIn: boolean = false;
isAdmin: boolean = false;
token: string | null = null;
username: string = '';
alarms:any = [];
private API_ENDPOINTS = {
// login: '/user/login',
login: 'user/currentUser?auth'
}
constructor(private http: HttpClient, public cumulocityService:CumulocityService) {
console.log("cumulocityService", this.cumulocityService.client);
debugger;
this.cumulocityService.client.alarm.list$().subscribe((data) => this.alarms = data);
this.loadToken();
}
}
c8y.service.ts - Actually i took it from your example which you had already given in another question. The same code i took it from that fiddle example.
import { Injectable } from '#angular/core';
import { Client } from '#c8y/client';
#Injectable()
export class CumulocityService {
public client: Client;
constructor() {}
}
versions
npm --version
5.6.0
node --version
v8.11.3

The reasons for that are very strict settings in your Typescript compiler:
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "./",
"module": "es2015",
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
"strictNullChecks": true, /* Enable strict null checks. */
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
"noUnusedLocals": true, /* Report errors on unused locals. */
"noUnusedParameters": true, /* Report errors on unused parameters. */
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}
These settings might be good if you use them on your project but can harm other libs (e.g. our #c8y/client lib) that are built with not so strict settings. So either remove those settings or exclude node_modules (last I haven't tried but should work as well):
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "./",
"module": "es2015",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}

Related

How to correctly add preset to Vuetify?

I use Vuetify2 and have a problem adding preset to my Vue2 app. There are errors thrown up. I installed preset through vue add vuetify-preset-rally and then added to vuetify.js as follows:
import Vue from 'vue';
import Vuetify from 'vuetify/lib/framework';
import { preset } from 'vue-cli-plugin-vuetify-preset-rally/preset'
Vue.use(Vuetify);
export default new Vuetify({
preset,
rtl: true,
theme: {dark : true}
});
I followed official Vuetify documentation. I got a bunch of errors, most of them are sth like this:
ERROR in ./node_modules/vuetify/src/styles/main.sass
(./node_modules/css-loader/dist/cjs.js??clonedRuleSet-29.use[1]!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-29.use[2]!./node_modules/sass-loader/dist/cjs.js??clonedRuleSet-29.use[3]!./node_modules/vuetify/src/styles/main.sass)
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
ValidationError: Invalid options object. Sass Loader has been
initialized using an options object that does not match the API
schema.
options has an unknown property 'prependData'. These properties are valid: object { implementation?, sassOptions?, additionalData?,
sourceMap?, webpackImporter? }
at validate (D:\SalesCore\salescore\node_modules\sass-loader\node_modules\schema-utils\dist\validate.js:105:11)
at Object.loader (D:\SalesCore\salescore\node_modules\sass-loader\dist\index.js:30:29)
I also tried to add the whole string to preset but it doesn't change anything:
export default new Vuetify({
preset: 'vue-cli-plugin-vuetify-preset-rally/preset',
rtl: true,
theme: {dark : true}
});
My package.json:
{
"name": "salescore",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"core-js": "^3.8.3",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
"vuetify": "^2.6.0",
"vuex": "^3.6.2"
},
"devDependencies": {
"#vue/cli-plugin-babel": "~5.0.0",
"#vue/cli-plugin-router": "~5.0.0",
"#vue/cli-plugin-vuex": "~5.0.0",
"#vue/cli-service": "~5.0.0",
"sass": "~1.32.0",
"sass-loader": "^10.0.0",
"vue-cli-plugin-vuetify": "~2.5.8",
"vue-cli-plugin-vuetify-preset-rally": "~1.0.4",
"vue-template-compiler": "^2.6.14",
"vuetify-loader": "^1.7.0"
}
}
Why there are problems and how to overcome it? I use v-app in my application.
EDIT:
I installed some dependencies and configured my webpack through vue.config.js. Just copied snippet from official docs but there is some problem with this webpack (I used vue inspect to check if all is ok and snippet was added to webpack) - it throws an error on compilation:
vue.config.js
const { defineConfig } = require('#vue/cli-service')
module.exports = defineConfig({
transpileDependencies: [
'vuetify'
],
configureWebpack: {
rules: [
{
test: /\.s(c|a)ss$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
// Requires sass-loader#^7.0.0
options: {
implementation: require('sass'),
indentedSyntax: true // optional
},
// Requires >= sass-loader#^8.0.0
options: {
implementation: require('sass'),
sassOptions: {
indentedSyntax: true // optional
},
},
},
],
},
],
}
})
Error:
ValidationError: Invalid configuration object. Webpack has been
initialized using a configuration object that does not match the API
schema.

react-native-testing-library with typescript does not work

I've tried for days many ways to set up #testing-library/react-native with typescript following a sort of guides but still not able to render a simple component.
Roughly, my stack is react native with typescript and jest with ts-jest and react-native-testing-library. I'm following these guidelines among others:
Typescript React Native with Jest
Using TypeScript with React Native
Using with React Native
This is the error I'm getting for the simple test component below:
ReferenceError: React is not defined
Component:
import React from 'react'
import { View, Text } from 'react-native'
const SomeComponent = () => {
return (
<View>
<Text>Hello</Text>
</View>
)
}
export default SomeComponent
Test:
import { render } from '#testing-library/react-native'
import SomeComponent from './SomeComponent'
describe('<SomeComponent>', () => {
it('should render some component', () => {
const { getByText } = render(<SomeComponent />)
expect(getByText(/hello/i)).toBeDefined()
})
})
Follow a bunch of configurations for reference:
Dependencies:
{
"name": "connect",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start",
"debug": "open 'rndebugger://set-debugger-loc?host=localhost&port=8081' && react-native start",
"android": "react-native run-android",
"ios": "react-native run-ios",
"pod": "npx pod-install",
"test": "jest",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx"
},
"dependencies": {
"#airbrake/browser": "^2.1.7",
"#react-navigation/bottom-tabs": "^6.2.0",
"#react-navigation/native": "^6.0.8",
"#react-navigation/native-stack": "^6.5.1",
"#reduxjs/toolkit": "^1.8.0",
"#rneui/base": "^4.0.0-rc.1",
"#rneui/themed": "^4.0.0-rc.1",
"#types/react": "^17",
"#types/react-native-dotenv": "^0.2.0",
"#types/react-redux": "^7.1.23",
"axios": "^0.26.1",
"formik": "^2.2.9",
"http-status": "^1.5.0",
"moment": "^2.29.2",
"react": "17.0.2",
"react-native": "0.67.4",
"react-native-blob-util": "^0.13.8",
"react-native-dotenv": "^3.3.1",
"react-native-dropdownalert": "^4.5.1",
"react-native-error-boundary": "^1.1.12",
"react-native-loading-spinner-overlay": "^2.0.0",
"react-native-safe-area-context": "^4.2.2",
"react-native-screens": "^3.13.1",
"react-native-splash-screen": "^3.3.0",
"react-native-vector-icons": "^9.1.0",
"react-redux": "^7.2.6",
"redux-persist": "^6.0.0",
"redux-persist-filesystem-storage": "^4.0.0",
"use-debounce": "^7.0.1",
"yup": "^0.32.11"
},
"devDependencies": {
"#babel/core": "^7.12.9",
"#babel/preset-env": "^7.16.11",
"#babel/runtime": "^7.12.5",
"#react-native-community/eslint-config": "^3.0.1",
"#testing-library/jest-native": "^4.0.4",
"#testing-library/react-native": "^9.1.0",
"#types/jest": "^27.4.1",
"#types/react-native": "^0.66.15",
"#types/react-native-loading-spinner-overlay": "^0.5.3",
"#types/react-test-renderer": "^17.0.1",
"babel-jest": "^27.5.1",
"eslint": "7.32.0",
"jest": "^27.5.1",
"metro-react-native-babel-preset": "^0.70.1",
"react-addons-test-utils": "^15.6.2",
"react-native-typescript-transformer": "^1.2.13",
"react-test-renderer": "18.0.0",
"ts-jest": "^27.1.4",
"typescript": "^4.4.4"
},
"resolutions": {
"#types/react": "^17"
}
}
jest.config.js
const { defaults: tsjPreset } = require('ts-jest/presets')
module.exports = {
...tsjPreset,
preset: 'react-native',
transform: {
...tsjPreset.transform,
'\\.js$': '<rootDir>/node_modules/react-native/jest/preprocessor.js',
},
globals: {
'ts-jest': {
babelConfig: true,
},
},
transformIgnorePatterns: [
'/node_modules/(?!(#rneui|#react-native|react-native|react-native-size-matters|react-native-ratings|redux-persist-filesystem-storage|react-native-blob-util)/)',
],
setupFiles: ['./jest.setup.js'],
cacheDirectory: '.jest/cache',
}
babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module:react-native-dotenv',
{
moduleName: 'react-native-dotenv',
},
],
],
}
tsconfig.json
{
"compilerOptions": {
"target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"lib": ["es2017"], /* Specify library files to be included in the compilation. */
"allowJs": true, /* Allow javascript files to be compiled. */
"jsx": "react-native", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
"noEmit": true, /* Do not emit outputs. */
"isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
"strict": true, /* Enable all strict type-checking options. */
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"skipLibCheck": false, /* Skip type checking of declaration files. */
"resolveJsonModule": true /* Allows importing modules with a ‘.json’ extension, which is a common practice in node projects. */
},
"exclude": [
"node_modules", "babel.config.js", "metro.config.js", "jest.config.js"
]
}
tsconfig.spec.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"jsx": "react"
}
}
rn-cli.config.js
module.exports = {
getTransformModulePath() {
return require.resolve('react-native-typescript-transformer')
},
getSourceExts() {
return ['ts', 'tsx']
},
}
There is a similar open question about this setup here Setup for React Native/TypeScript/Testing Library/Jest not working
Thanks!
You need run npm install #babel/plugin-transform-react-jsx --save-dev into terminal and add plugin into babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module:react-native-dotenv',
{
moduleName: 'react-native-dotenv',
},
],
// add new plugin
[
'#babel/plugin-transform-react-jsx',
{
runtime: 'automatic',
},
],
],
}
You can use the official RNTL example that showcases a proper RNTL which also includes TypeScript.
Config issues like yours are hard to resolve as some small hard to notice issues might easily break the setup, so it's usually easiest to start with working setup.

vue.js - dynamic imports results in error: Support for the experimental syntax 'dynamicImport' isn't currently enabled

I'm learning Vue.js with Webpack for the first time today and trying to get a router working with lazy/dynamic imports.
I want to use lazy/dynamic imports because I am rebuilding my content management system which has many, many pages that may or may not be used during the user's session, so loading the modules they need dynamically, when they need them, makes more sense with regards to my application.
My very basic router currently looks like this:
import Vue from "vue";
import Router from "vue-router";
Vue.use(Router);
function loadView(view) {
return () => import(/* webpackChunkName: "view-[request]" */ `#/views/${view}.vue`);
}
export default new Router({
routes: [
{
path: "/",
name: "dashboard",
component: loadView("Dashboard")
},
{
path: "/login",
name: "login",
component: loadView("Login")
}
]
});
However, I run into the following compilation error:
ERROR in ./src/router/index.js Module build failed (from
./node_modules/babel-loader/lib/index.js): SyntaxError:
...../src/router/index.js: Support for the experimental syntax
'dynamicImport' isn't currently enabled
With the additional note:
Add #babel/plugin-syntax-dynamic-import to the
'plugins' section of your Babel config to enable parsing.
And shows me which line is the problem, which is quite obvious anyway:
return () => import(/*..........
^
I recognise this error from when I was playing with Webpack on its own a few months ago, so I knew I had to install the dynamic import plugin to make this work.
This is what I installed:
npm install babel-plugin-syntax-dynamic-import
And I made this plugin available in my babel.rc configuration file and ran npm run dev to recompile everything:
{
"presets": [
[
"#babel/env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}
]
],
"plugins": ["#babel/plugin-syntax-dynamic-import"]
}
But I'm still getting the error and I still can't use dynamic importing features! Am I doing something wrong? Has anybody else had trouble with getting dynamic imports to work?
My webpack.config file:
'use strict';
const webpack = require('webpack');
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
mode: 'development',
entry: [
'./src/app.js'
],
devServer: {
hot: true,
watchOptions: {
poll: true
}
},
module: {
rules: [
{
test: /\.vue$/,
use: 'vue-loader'
},
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
sourceMap: true,
outputStyle: 'compressed',
data: `
#import "./src/assets/scss/_variables.scss";
#import "./src/assets/scss/_mixins.scss";
`
}
}
]
}
]
},
resolve: {
alias: {
"#": path.resolve(__dirname, './src'),
"Components": path.resolve(__dirname, './src/components/')
}
},
optimization: {
minimizer: [new UglifyJsPlugin()],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
})
]
}
My package.json file:
{
"name": "manage_v2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --config build/webpack.config.dev.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.18.0",
"vue": "^2.5.22",
"vue-router": "^3.0.2",
"vuex": "^3.1.0"
},
"devDependencies": {
"#babel/core": "^7.2.2",
"#babel/plugin-syntax-dynamic-import": "^7.2.0",
"#babel/preset-env": "^7.3.1",
"babel-loader": "^8.0.5",
"babel-plugin-dynamic-import-webpack": "^1.1.0",
"css-loader": "^2.1.0",
"html-webpack-plugin": "^3.2.0",
"node-sass": "^4.11.0",
"sass-loader": "^7.1.0",
"uglifyjs-webpack-plugin": "^2.1.1",
"vue-loader": "^15.6.2",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.5.22",
"webpack": "^4.29.0",
"webpack-cli": "^3.2.1",
"webpack-dev-server": "^3.1.14"
}
}
I fixed the problem myself after many hours of frustration. I still don't know why the method that's used in the Babel, Webpack and Vue documentation doesn't work but I did get this working:
I first removed the plugin declaration from babel.rc file and then added an option to the babel loader in webpack.config file:
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
plugins: [
"#babel/plugin-syntax-dynamic-import"
]
}
}
}
I hope this helps others.
You have the wrong plugin assignment:
"plugins": ["#babel/plugin-syntax-dynamic-import"]
Would be the correct format for that plugin.

jest.mock() not mocking module in Babel 7 and React-Native 0.56

Like MANY others, I'm trying to upgrade my RN app to React-Native 0.56 and Babel is making everything so easy! (Not the sarcasm here) I could update RN, React to the latest and make my app compile and work, but the tests (jest) are not working anymore.
But not all the test. I manage to solve almost all the different kinds of issue, expect this one:
meeting actions › creates CLEAR_CURRENT_ATTACHMENTS when clearning current attachments
TypeError: eventActions.refreshEvents.mockImplementation is not a function
90 |
91 | beforeEach(() => {
> 92 | eventActions.refreshEvents.mockImplementation(() => ({ type: DUMMY_TYPE }));
| ^
93 | MockDate.set(A_DATE);
94 | store = mockStore({
95 | authentication: {
at Object.<anonymous> (src/calendar/actions/__tests__/meetingActions-test.js:92:32)
Test file with the test failing (Remove all the others test to simplify the example)
import moment from 'moment';
import MockDate from 'mockdate';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import getToken from 'authentication/selectors/tokenSelector';
import * as actions from '../meetingActions';
import * as eventActions from '../eventActions';
import { getPlannerComments } from '../../selectors/scheduleModificationSelectors';
const {
CLEAR_CURRENT_ATTACHMENTS,
} = actions;
jest.mock('../eventActions.js');
jest.mock('../../../authentication/selectors/tokenSelector');
jest.mock('../../selectors/scheduleModificationSelectors');
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
describe('meeting actions', () => {
const A_TOKEN = 'token12345';
const AN_ID = 'h1234';
const A_DATE = moment('2016-08-22T21:00:00.000Z');
const AN_MEETING_EVENT = {
start: A_DATE,
end: A_DATE,
guests: [],
newGuests: [],
newAttachments: [],
contactsToAddToGuestList: [],
groupsToAddToGuestList: [],
listsToAddToGuestList: [],
};
const AN_ACCOUNT = { id: AN_ID };
const DUMMY_TYPE = 'Dummy type';
const PLANNER_COMMENTS = {};
let store;
beforeEach(() => {
eventActions.refreshEvents.mockImplementation(() => ({ type: DUMMY_TYPE }));
MockDate.set(A_DATE);
store = mockStore({
authentication: {
token: A_TOKEN,
},
session: {
account: AN_ACCOUNT,
},
meeting: AN_MEETING_EVENT,
event: {
attendees: [],
},
});
getToken.mockImplementation(() => A_TOKEN);
getPlannerComments.mockImplementation(() => PLANNER_COMMENTS);
});
it('creates CLEAR_CURRENT_ATTACHMENTS when clearing current info', () =>
store.dispatch(actions.clearCurrentInfo())
.then(() => {
expect(store.getActions()).toContainEqual({ type: CLEAR_CURRENT_ATTACHMENTS });
}));
afterEach(() => {
MockDate.reset();
});
});
I have over 800 tests that failed because of this error. From what I understood of the problem, it comes from the fact that the jest.mock
jest.mock('../domain/Attachment') // For example
is not actually mocking the class. So Attachment looks like the normal class. And so the mockImplementation of a function cause the undefined is not a function
{ [Function: Record]
iconOf: [Function: iconOf],
iconColorOf: [Function: iconColorOf],
getCleanName: [Function: getCleanName],
open: [Function: _callee2],
parse: [Function: parse] }
Package.json
{
"name": "MY APP",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest",
"ios": "react-native run-ios",
"android": "react-native run-android",
"test:watch": "npm run test -- --watch",
"lint": "eslint src --max-warnings=0",
"install-dep": "npm install && cd ios && pod install"
},
"rnpm": {
"assets": [
"./src/main/themes/fonts/assets"
]
},
"jest": {
"moduleDirectories": [
"node_modules",
"src"
],
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js"
},
"preset": "react-native",
"collectCoverage": true,
"setupTestFrameworkScriptFile": "<rootDir>/setup-jasmine-env.js",
"moduleFileExtensions": [
"js",
"json",
"es6",
"ios.js",
"android.js"
],
"setupFiles": [
"./testenv.js"
],
"transformIgnorePatterns": [
"node_modules/?!(react-native)"
]
},
"dependencies": {
"bluebird": "^3.4.6",
"buffer": "^5.0.0",
"color": "^2.0.0",
"deepmerge": "^1.5.2",
"diacritics": "^1.2.3",
"immutable": "^3.8.2",
"linkify-it": "^2.0.3",
"lodash.debounce": "^4.0.8",
"moment": "^2.17.0",
"prop-types": "^15.6.0",
"react": "16.4.1",
"react-native": "0.56.0",
[...] // Lots of dependencies not related to the problem
"react-navigation": "1.5.11",
"react-redux": "^5.0.7",
"redux": "^3.7.2",
"redux-thunk": "^2.2.0",
"reselect": "^3.0.1",
"socket.io-client": "2.1.0"
},
"devDependencies": {
"#babel/core": "^7.0.0",
"babel-core": "^6.26.3",
"babel-eslint": "7.2.3",
"babel-jest": "^23.4.2",
"babel-plugin-module-resolver": "^3.1.1",
"babel-preset-react-native": "5.0.2",
"eslint": "^3.11.1",
"eslint-config-airbnb": "^13.0.0",
"eslint-import-resolver-babel-module": "5.0.0-beta.0",
"eslint-plugin-import": "^2.12.0",
"eslint-plugin-jsx-a11y": "^2.2.3",
"eslint-plugin-react": "^6.7.1",
"eslint-plugin-react-native": "^2.2.0",
"fetch-mock": "^5.1.2",
"istanbul": "0.4.5",
"jasmine-reporters": "^2.2.0",
"jest": "^23.5.0",
"jest-cli": "23.5.0",
"mockdate": "^2.0.1",
"moment-timezone": "^0.5.20",
"react-dom": "16.4.2",
"react-test-renderer": "16.4.2",
"redux-mock-store": "1.3.0",
"regenerator-runtime": "^0.12.1",
"remote-redux-devtools": "^0.5.7"
}
}
Note that like multiple issue in Jest, Babel and React-Native GitHubs, I have the Transform.
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js"
},
.babelrc
{
"presets": ["react-native"],
"plugins": [
[
"module-resolver",
{
"root": ["./src"],
"extensions": [".js", ".ios.js", ".android.js"]
}
]
]
}
Anyone has any idea?
If you look at the example here, you'll see that mockImplementation can only be called on a jest.fn() object. In your case, you'll need to first mock refreshEvents and then call mockImplementation on that mock:
...
eventActions.refreshEvents = jest.fn();
eventActions.refreshEvents.mockImplementation(() => ({ type: DUMMY_TYPE }));
...
If you want to keep the code you've posted as it is, then you'll have to create a subdirectory __mock__ adjacent to your mocked out module and create a file that mocks functions in that module within that subdirectory as explained here.
UPDATE:
jest.mock calls are automatically hoisted to the top of the file with the babel-jest transformer, which is what you need. Note that you are already using a jest transformer. From the docs:
If you are using the babel-jest transformer and want to use an additional code preprocessor, keep in mind that when "transform" is overwritten in any way the babel-jest is not loaded automatically anymore. If you want to use it to compile JavaScript code it has to be explicitly defined.
That means you have to explicitly include the babel-jest transform in your jest config in package.json. That should fix things.

Webpack 2 bundle typescript files with same namespace into a single file

I am new to Webpack and bundling typescript files into a single file. I got the following setup where I would like to achieve a single JS files with all my typescript bundled.
tsconfig.json:
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"noEmitOnError": true,
"noImplicitAny": false,
"removeComments": true,
"sourceMap": true,
"target": "es6",
"moduleResolution": "node"
},
"exclude": [
"node_modules",
"libs"
]
}
Webpack.config.js
var path = require("path");
const { CheckerPlugin } = require('awesome-typescript-loader');
const config = {
entry: {
Bootstrap: "./Bootstrapper.ts"
},
output: {
//output file naming conventions https://webpack.js.org/configuration/output/#output-filename when having more different configs with outputs
filename: "[name].bundle.js",
path: path.resolve(__dirname, "wwwroot/dist")
},
context: path.resolve(__dirname, "App"),
devtool: "inline-source-map",
module: {
rules: [
{
test: /\.tsx?$/,
loader: "awesome-typescript-loader"
}
]
},
plugins: [
new CheckerPlugin()
]
}
module.exports = config;
Bootstrap typescript file where I incude some node_module that actually work. JQuery works for instance. But If I try to use the class and subclasses that I use from a single namespace I walk against a wall.
Bootstrapper.ts
import * as $ from "jquery";
import * as Konva from "konva";
import * as SignalR from "#aspnet/signalr";
import * as ko from "knockout";
//How do I use these classes that are in different files
import App = Project.Web.Core.App;
$("document").ready(() => {
let app = new App();
alert("This works if I leave the App reference out!");
});
This is the App.ts that I try to use (import App = Project.Web.Core.App;)
namespace Project.Web.Core {
export class App {
pageId: number = 0;
pageRequestId: string = "";
//drawingManager = new Managers.KonvaDrawManager();
signalRmanager = new Managers.SignalRmanager("");
constructor() {
$("document").ready(() => {
this.pageId = $("#container").data("pageid");
this.pageRequestId = $("#container").data("pagerequestid");
this.signalRmanager.pageRequestId = this.pageRequestId;
//this.signalRmanager.setupSignalRConnection(this.drawingManager);
this.loadCanvasData();
});
window.onresize = () => {
//this.drawingManager.rescale();
};
window.onunload = () => {
this.signalRmanager.notifyPageUnloaded();
}
}
loadCanvasData() {
this.pageId = $("#container").data("pageid");
$.get({
dataType: "json",
url: `api/page/${this.pageId}/stage`,
success: (data: any) => {
//this.drawingManager.initializeStage(data);
},
complete: (data: any) => {
if (data.status === 200) {
this.signalRmanager.notifyPageLoaded();
}
}
});
}
}
}
Packages I use
{
"name": "Project.Web_core",
"private": true,
"version": "0.0.0",
"scripts": {
"build": "./node_modules/.bin/webpack -d",
"build:prod": "./node_modules/.bin/webpack -p",
"watch": "./node_modules/.bin/webpack --watch",
"dev": "./node_modules/.bin/webpack-dev-server"
},
"devDependencies": {
"#types/jquery": "^3.3.1",
"#types/knockout": "^3.4.53",
"#types/knockout.mapping": "^2.0.33",
"#types/webpack-env": "1.13.5",
"aspnet-prerendering": "^3.0.1",
"aspnet-webpack": "^2.0.3",
"awesome-typescript-loader": "^5.0.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"event-source-polyfill": "0.0.12",
"json-loader": "0.5.7",
"node-sass": "^4.8.3",
"sass-loader": "^6.0.7",
"style-loader": "0.20.1",
"typescript": "2.7.1",
"uglifyjs-webpack-plugin": "^1.2.4",
"webpack": "^4.5.0",
"webpack-cli": "^2.0.14",
"webpack-dev-middleware": "^3.1.2",
"webpack-dev-server": "^3.1.3",
"webpack-merge": "4.1.1"
},
"dependencies": {
"#aspnet/signalr": "^1.0.0-preview1-update1",
"es5-shim": "^4.5.10",
"es6-shim": "^0.35.3",
"jquery": "3.3.1",
"knockout": "^3.4.2",
"knockout-mapping": "^2.6.0",
"konva": "^2.0.2",
"watchpack": "^1.4.0"
}
}
I hope someone can help me out clearify my wrong way of thinking.
There are several things:
Typescript config, you can copy. With your types
change import export and remove namespace
export class App { ... }
import { App } from '/path/to/your/file';
class needs a destroyer
and finally in webpack.config.js you can set properties
entry: {
Bootstrap: "./Bootstrapper.ts",
namespace: "./path-to-your-namespace.ts",
anotherNamespace: "./path-to-your-anotherNamespace.ts"
},
resolve: {
extensions: ['.js', '.ts', '.json']
}