Ionic 2 import libraries - ionic2

I am trying to implement crypto-js with Ionic 2.
I have done the following:
npm install crypto-js
typings install dt~crypto-js --global --save
My index.d.ts now contains:
/// <reference path="globals/crypto-js/index.d.ts" />
A crypto-js folder has been created under ./typings/global
I then try the following code:
declare var require: any;
import * as CryptoJS from 'crypto-js';
...
private CryptoJS: any;
constructor() {
this.CryptoJS = require("crypto-js");
}
test() {
alert(this.CryptoJS);
}
As soon as I try reference this.CryptoJS (i.e alert(this.CryptoJS)) the app crashes.
I am doing something wrong in the way I import the crypto-js libraries. Please can anyone advise?
Thanks
UPDATE:
following this, I run:
>npm install --save #types/cryptojs
npm WARN package.json theWhoZoo# No repository field.
npm WARN package.json theWhoZoo# No README data
npm WARN package.json theWhoZoo# No license field.
#types/cryptojs#3.1.29 node_modules\#types\cryptojs
How do I import CryptoJS in the code?
Thanks
UPDATE:
import { Injectable } from "#angular/core";
import { LanguageModel } from './languageModel';
import { LocationModel } from './locationModel';
import { JobModel } from './jobModel';
import 'crypto-js';
#Injectable()
export class PersonModel {
public id: number = null;
public joiningDate: number = null;
public lastAccessDate: number = null;
public userName: string = null;
public password: string = null;
public firstName: string = null;
public lastName: string = null;
public emailAddress: string = null;
public locations: LocationModel[] = [];
public languages: LanguageModel[] = [];
public time: string = null;
public avatar: string = null;
public avatar64: string = null;
//private CryptoJS: any;
private SECERET_KEY: string = 'secret key 123';
public getPasswordEcrypted(): string {
// Decrypt
var bytes = CryptoJS.AES.decrypt(this.password.toString(), this.SECERET_KEY);
var plaintext = bytes.toString(CryptoJS.enc.Utf8);
console.log('getPasswordEcrypted', plaintext);
return plaintext;
}
public setPasswordEncrypted(password: string): void {
// Encrypt
alert(password);
console.log('setPasswordEncrypted', password, CryptoJS);
alert(CryptoJS);
var ciphertext = CryptoJS.AES.encrypt(password, this.SECERET_KEY);
alert(ciphertext);
console.log('setPasswordEncrypted', password, ciphertext);
this.password = ciphertext;
}
}
UPDATE:
Changing to:
import CryptoJS from 'crypto-js';
results in:
UPDATE:
Running this:
typings install dt~crypto-js --global --save
results in no build errors, but at run time when CryptoJS is accessed (e.g. console.log(CryptoJS);), the app crashes.

Here is the solution for this.
After you install the npm libraries
npm install crypto-js #types/cryptojs --save
Create a declaration.d.ts file under src and add declaration to the module. This resolves your module undefined issue.
declare module 'crypto-js';
Within the service class itself add the import CrytoJS from the module like this:
import CryptoJS from 'crypto-js';
Now in your code you can reference CryptoJS. For, example:
let obj = CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(['abcd', this.config.salt].join(':'), this.config.salt));
console.log(obj);
outputs:
t2eCyUuZMKRNTRqCW0L5KRvMjWhLV887h1ehjCNSr2c=

I don't know if this subject is closed or not and i've just solved the same problem for me, so...
Actually, it seems like you just have to install crytpoJS with :
npm install crypto-js --save
And import the precise file/library you want to use with :
import { SHA3 } from "crypto-js"; // SHA3 one-way encryption
import { AES } from 'crypto-js'; // For AES encryption/decryption
import { enc } from 'crypto-js'; // For characters encodages types (Utf-8, latin1...)
Now you can use CryptoJs functions by using directly the name of imported library :
//AES
let encrypted = AES.encrypt('my message', 'secret key 123');
let bytes = AES.decrypt(encrypted.toString(), 'secret key 123');
let decrypted = bytes.toString(enc.Utf8);
//SHA
let hash = SHA3('password', { outputLength: 224 }).toString()
Maybe it'll help someone, some day...
Regards.

You were right to switch to types because ionic uses #types and not typings.
First of all
import * as CryptoJS from 'crypto-js';
Should be
import 'crypto-js';
In this specific case crypto js is not a proper node module so the import is to the general file
There is also no require in typescript unless you installed it, instead you have import. So this doesn't make sense:
this.CryptoJS = require("crypto-js");
This declares an empty variable of any:
private CryptoJS: any;
If you translate it to javascript it would look like this:
var CryptoJS;
So this is basically very much redundant. You already have the variable from the import
In Summary this should be your code:
import CryptoJS from 'crypto-js';
class SomeClass{
test(){
alert(CryptoJS);
}
}

Related

Could I use pinia without installing vue?

How could i use pinia without vue and vite?
"dependencies": {
"pinia": "^2.0.11",
"vite": "^2.7.13",
"vue": "^3.2.30"
}
I try to use pinia like this:
import { createApp } from 'vue';
import { useLoginStore } from './src/index.js';
import { createPinia } from 'pinia';
const pinia = createPinia();
const app = createApp({
data() {
return {};
}
});
app.use(pinia);
const useState = useLoginStore();
console.log(`<<<<01-24 08:52:27>>>>⬇️\n✨`, `useState`, useState);
and i use node to run it: node test
But it return error
Cannot find package '#vue/composition-api' imported from ...\node_modules\vue-demi\lib\index.mjs
Assume that your node test means running test.js, with the content in the file like what you mentioned in the question and no bugs happened in useLoginStore, your code should run fine since I can run your example functionally.
For the Cannot find package questions, I suggest you delete the node_modules directory and reinstall packages by typing npm install.
If you are asking if Pinia can run without installing Vue, the answer is simply no, since Pinia needs to be activated by Vue. You will face the following error if trying to run Pinia without Vue:
import { defineStore } from 'pinia'
const useLoginStore = defineStore('login', { /* Options */ });
const useState = useLoginStore();
console.log( useState );
Error: [🍍]: getActivePinia was called with no active Pinia. Did you forget to install pinia?
const pinia = createPinia()
app.use(pinia)
This will fail in production.
References:
https://vuejs.org/api/application.html#app-use
https://github.com/vuejs/pinia/discussions/664
https://github.com/vuejs/pinia/discussions/1238

Vue JS - Unit test - localstorage is not defined

I'm writing unit test for for vue cli 3 using Mocha and chai. I have tried mocking localstorage. but still getting this error - 'localStorage is not defined'. Can anyone please help me here?
My code is like this -
import { expect, assert } from 'chai';
import { shallowMount } from '#vue/test-utils';
import LoginComponent from '#/views/LoginComponent.vue';
import Constants from '#/constants';
declare var global: any;
let wrapper;
let componentInstance: any;
let authData;
var mockLocalStorage = {
getItem(key: any) {
if (key === 'access_token') { return '/* a token object */'; }
return 'null';
}
};
describe('LoginComponent.vue', () => {
beforeEach(() => {
global.window = { localStorage: mockLocalStorage };
authData = JSON.stringify(Constants.AUTH_DATA);
wrapper = shallowMount(AliUMSLoginComponent, {
propsData: { authData }
});
componentInstance = wrapper.vm;
});
it('has a created hook', () => {
assert.isNotNull(componentInstance.authData);
});
});
For anyone else who might stumble upon this question - the following worked for me:
1) Create a setup.js file in your unit test folder and add the following code:
require('jsdom-global')();
global.localStorage = window.localStorage;
After fixing the "localStorage is undefined" error, you might experience additional errors (like I did). In the end the following code snippet fixed everything:
require('jsdom-global')(undefined, { url: 'https://localhost' });
global.localStorage = window.localStorage;
global.sessionStorage = window.sessionStorage;
window.Date = Date;
... You can find more info on this here: vuejs/vue-cli/issues/2128 and here: vuejs/vue-test-utils/issues/936
2) Update the test script in your package.json file to load the setup file you just created:
"test:unit": "vue-cli-service test:unit --require tests/unit/setup.js"
I got your solution to work however when trying to grep for one file to run, it runs all files.
Is there a better way to include this maybe with an include at the top of the file? An include usually has a method that returns something. hmmmm how to do this?
Is this the correct syntax for the package.json file:
"test:unit-filter": "vue-cli-service test:unit --require tests/unit/helpers/setup.js --watch --grep"

Mock this.$parent.$on with jest

We are using vuejs, typescript, vuex and jest. We are currently using test-utils to mock the store.
But I cannot find out how to mock a call to this.$parent.$on
Here is one of our components (very simplified):
AnalysisList.ts:
import Component from 'vue-class-component'
import {Getter} from 'vuex-class'
import {UserVO} from '#/valueObjects/UserVO'
import {Vue} from 'vue-property-decorator'
#Component
export default class AnalysisList extends Vue {
#Getter('getCurrentUser') private currentUser: UserVO
private searchString = ''
public mounted() {
this.$parent.$on('resetAnalyses', this.reset)
}
public reset() {
this.searchString = ''
}
}
AnalysisList.vue:
<template lang="pug">
text test
</template>
<script lang="ts" src="./AnalysisList.ts">
</script>
AnalysisList.spec.ts:
import {shallowMount} from '#vue/test-utils'
import AnalysisList from '#/components/analysis/AnalysisList'
import Vuex from 'vuex'
import {Vue} from 'vue-property-decorator'
import VueRouter from 'vue-router'
Vue.use(Vuex)
Vue.use(VueRouter)
describe('AnalysisList.vue', () => {
const store = new Vuex.Store( {
modules: {
user: {
state: {currentUser: 'test'},
getters: {
getCurrentUser: (state: any) => state.currentUser,
},
},
},
})
it('minimum test', (done) => {
const wrapper = shallowMount(AnalysisList, {store})
done()
})
})
When I run the test, I have the following error message, because $parent is not mocked:
TypeError: Cannot read property '$on' of undefined
at VueComponent.mounted (src/components/analysis/AnalysisList/AnalysisList.vue:73:20)
at callHook (node_modules/vue/dist/vue.runtime.common.js:2919:21)
at mountComponent (node_modules/vue/dist/vue.runtime.common.js:2800:5)
at VueComponent.Object.<anonymous>.Vue.$mount (node_modules/vue/dist/vue.runtime.common.js:7997:10)
at mount (node_modules/#vue/test-utils/dist/vue-test-utils.js:5381:8)
at shallowMount (node_modules/#vue/test-utils/dist/vue-test-utils.js:5414:10)
at Object.done (tests/unit/AnalysisList.spec.ts:20:53)
If I try to add a new property to shallowMount parameter:
const wrapper = shallowMount(AnalysisList, {store, parent: {$on: ()=>{}}})
I obtain a type error:
TS2345: Argument of type 'VueConstructor<Vue>' is not assignable to parameter of type 'FunctionalComponentOptions<Record<string, any>, PropsDefinition<Record<string, any>>>'.   Property 'functional' is missing in type 'VueConstructor<Vue>'.
Do you have any clue to help me mock this.$parent.$on ? Thanks.
I got the same issue with vue-test-utils and Jest (under the Vue, Vuex and Typescript environment)
For me, createLocalVue() of vue-test-utils library fixed the issue. This function creates a local copy of Vue to use when mounting the component. Installing plugins on this copy of Vue prevents polluting the original Vue copy. (https://vue-test-utils.vuejs.org/api/options.html#localvue)
Adding this to my test file fixed the issue:
const EventBus = new Vue();
const GlobalPlugins = {
install(v) {
// Event bus
v.prototype.$bus = EventBus;
},
};
// create a local instance of the global bus
const localVue = createLocalVue();
localVue.use(GlobalPlugins);
Hope this helps others, thanks :)

Ionic2: No provider Error

I am using Ionic2 rc4.
Your system information:
Cordova CLI: 6.4.0
Ionic Framework Version: 2.0.0-rc.4
Ionic CLI Version: 2.1.18
Ionic App Lib Version: 2.1.9
Ionic App Scripts Version: 1.0.0
ios-deploy version: Not installed
ios-sim version: Not installed
OS: macOS Sierra
Node Version: v6.9.4
Xcode version: Xcode 8.2.1 Build version 8C1002
I would like to add a service. I have other Services, that work perfectly. So I configure this new Service (PayPalService) the same.
payPalTest.ts
import { Component, Inject, forwardRef } from '#angular/core';
import { PayPalService } from '../paypal/PayPalService';
#Component({
templateUrl: 'payPalTest.html'
})
export class PayPalTestPage {
public payPalService: PayPalService = null;
constructor( #Inject(forwardRef(() => PayPalService)) payPalService) {
this.payPalService = payPalService;
}
public payOut(): void {
alert('payOut');
//this.payPalService.payOut();
}
}
payPalService.ts
declare var require: any;
var paypal = require('paypal-rest-sdk');
//import {paypal-rest-sdk} from './paypal-rest-sdk';
import { Injectable } from "#angular/core";
#Injectable()
export class PayPalService {
public paypal: any = null;
constructor() {
}
}
app.module.ts
import { PayPalService } from "../pages/paypal/payPalService";
import { PayPalTestPage } from "../pages/paypal/payPalTest";
...
#NgModule({
declarations: [
...
PayPalTestPage
...
entryComponents: [
...
PayPalTestPage
...
...
providers: [..., PayPalService]
However, I get the following error.
Error
Runtime Error Error in ./MyApp class MyApp - caused by: No provider
for PayPalService!
I think the error is related to the way I import the 'paypal-rest-sdk'.
declare var require: any;
var paypal = require('paypal-rest-sdk');
I installed the paypal-rest-sdk as follows:
npm install paypal-rest-sdk
And the new package has been added to the node_modules.
Question
Can anyone please suggest how I can resolve the above error please?
UPDATE
If I remove all reference to the PayPal api by commenting out the following two lines:
payPalService.ts
// declare var require: any;
// var paypal = require('paypal-rest-sdk');
I get the following error:
Error
Runtime Error Module build failed: Error: ENOENT: no such file or
directory, open
'/Users/richardmarais/Development/ionic/theWhoZoo/src/pages/paypal/payPalService.js'
at Error (native)
It was a really silly mistake by me. The import had the incorrect case.
Change:
payPalTest.ts
import { PayPalService } from '../paypal/PayPalService';
to:
import { PayPalService } from '../paypal/payPalService';

Ionic2: Runtime Error Cannot read property 'prototype' of undefined

I am using Ionic2 and am getting this error:
Runtime Error
Cannot read property 'prototype' of undefined
Reading here and here, it suggests it could be related to the order in which a subclass and baseclass are declared. I am using a baseclass with a subclass. Where do you change the order in which they are declared, is it in the imports? In what file?
Funny thing is my code was working fine, and suddenly started to get this error, even without me changing the base or sub classes. I did make a change to another file, which I have now reverted, but still get the error.
More details:
Error:
main.js:24046Uncaught TypeError: Cannot read property 'prototype' of undefined
at __extends (main.js:24046)
at job.ts:26
at Object.<anonymous> (job.ts:24)
at __webpack_require__ (bootstrap cdd11c2…:19)
at Object.<anonymous> (main.js:46012)
at __webpack_require__ (bootstrap cdd11c2…:19)
at Object.<anonymous> (personModel.ts:21)
at __webpack_require__ (bootstrap cdd11c2…:19)
at Object.<anonymous> (locationModel.ts:11)
Code:
job.ts
import { Component, ViewChild, ChangeDetectionStrategy, ChangeDetectorRef } from '#angular/core';
import { NavController, NavParams, InfiniteScroll, Content, Platform, Events, AlertController, LoadingController, ViewController, PopoverController } from 'ionic-angular';
import { JobModel } from '../model/jobModel';
import { PersonModel } from '../model/personModel';
import { SubCategoryModel } from '../model/subCategoryModel';
import { LocationModel } from '../model/locationModel';
import { RatingModel } from '../model/ratingModel';
import { ReviewPage } from '../review/review';
import { ChatsPage } from '../chats/chats';
import { CategoryPage } from '../category/category';
import { PersonPage } from '../person/person';
import { MyCameraPage } from '../mycamera/mycamera';
import { JobService } from '../service/jobService';
import { PersonService } from '../service/personService';
import { RatingService } from '../service/ratingService';
import { UtilityService } from '../utils/utilityService';
import { SearchJobsParent } from '../searchjobs/searchjobsParent';
import { MapRangeService } from '../service/mapRangeService';
#Component({
selector: 'job',
templateUrl: 'job.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class JobPage extends SearchJobsParent {
#ViewChild(Content) content: Content;
.....
searchJobsParent.ts
...
#Component({
})
export class SearchJobsParent {
...
ionic info
Your system information:
Cordova CLI: You have been opted out of telemetry. To change this, run: cordova telemetry on.
6.4.0
Ionic Framework Version: 2.0.0-rc.4
Ionic CLI Version: 2.1.18
Ionic App Lib Version: 2.1.9
Ionic App Scripts Version: 1.0.0
ios-deploy version: Not installed
ios-sim version: Not installed
OS: macOS Sierra
Node Version: v6.9.4
Xcode version: Not installed
I solved this by using Composition instead of Inheritance.
You create an instance of the class you have the common functionality in:
myClas.ts
private someCommonClass: SomeCommonClass = null;
...
this.someCommonClass = new SomeCommonClass(platform, ref);
someCommonClass.ts
constructor(platform: Platform)
The very first comment here got me thinking right and led me to a solution. My problem was I was trying to import a class into my base class. The imported class wasn't being bundled in the right order. By switching the order of my import statements in app.component.ts I was able to solve the problem.
In app.component.ts:
Wrong
import { ListPage } from '../pages/list/list';
import { LoginPage } from "../pages/login/login";
This was wrong because ListPage extended AppPage (not listed here) which imported LoginPage.
Right
import { LoginPage } from "../pages/login/login";
import { ListPage } from '../pages/list/list';
this problem happen because you install Native plugin and this plugin extends from IonicNativePlugin for Example (Base64ToGallery, TextToSpeech, ...). So, this caused in conflict, Iremoved this extends and it is work...
Following this steps for Example to TextToSpeech Plugin:
in this Path YourProjectFolder\node_modules\#ionic-native\text-to-speech
open file index.d.ts
go to declaration to class:
export declare class TextToSpeech extends IonicNativePlugin{
/**
* This function speaks
* #param options {string | TTSOptions} Text to speak or TTSOptions
* #return {Promise<any>} Returns a promise that resolves when the speaking finishes
*/
speak(options: string | TTSOptions): Promise<any>;
/**
* Stop any current TTS playback
* #return {Promise<any>}
*/
stop(): Promise<any>;
}
Delete extends IonicNativePlugin and save.
That is all!
Did anybody try to provide a reference file with the correct order like this:
/// <reference path='SomeCommonClass.ts' />
/// <reference path='TheExtendingClass.ts' />