lodash functions are not recognizing in angular6 and jasmine test cases - jasmine

I am using lodash library in my angular application for trimming text box value.
The code am using like this
This is working fine when i run the app.
import _ from 'lodash';
validateForm() {
if(_.trim(this.addusermodel.firstname) == "") {
////
}
}
in spec file am using this code
describe('validateForm', () => {
it('Form should validate', () => {
component.addusermodel.firstname = "wrwer";
component.validateForm();
});
});
But when i executing the function from spec file am getting this error TypeError: Cannot read property 'trim' of undefined

Import lodash like this
import * as _ from "lodash"; instead of import _ from 'lodash';

Related

Vue 2 Nuxt directive image source won't work

Can someone tell me why this does not work in Nuxt, or how to fix it. The dataset.alt attribute is simply 'image.svg'
el.setAttribute('src', '~/assets/images/' + el.dataset.alt)
The answer was to use directive binding and to require the image. Full code for reference:
<img src="#/assets/images/light-image.svg" v-theme-image="require('#/assets/images/dark-image.svg')" />
import Vue from 'vue';
import VueCookies from 'vue-cookies'
Vue.use(VueCookies)
export const themeImage = {
inserted: (el, binding, vnode) => {
function init() {
if ($cookies.get('theme') === 'dark') {
el.setAttribute('src', binding.value);
}
}
init();
},
}
Vue.directive('theme-image', themeImage);

ReduxForm is rendered twice when mounted via enzyme

I'm trying to align my tests to follow breaking changes after upgrading react-redux to 6.0.0 and redux-form to 8.1.0 (connected components do not take store in props any longer)
I needed to wrap my connected component in from react-redux in tests and use mount to get to actual component but now ReduxForm is rendered twice.
I tried to use hostNodes() method but it returns 0 elements.
Any ideas how to fix it?
Here is the test:
import React from 'react'
import { mount } from 'enzyme'
import configureStore from 'redux-mock-store'
import { Provider } from 'react-redux'
import PasswordResetContainer from './PasswordResetContainer'
describe('PasswordResetContainer', () => {
it('should render only one ReduxForm', () => {
const mockStore = configureStore()
const initialState = {}
const store = mockStore(initialState)
const wrapper = mount(<Provider store={store}><PasswordResetContainer /></Provider>)
const form = wrapper.find('ReduxForm')
console.log(form.debug())
expect(form.length).toEqual(1)
})
And PasswordResetContainer looks like this:
import { connect } from 'react-redux'
import { reduxForm } from 'redux-form'
import PasswordReset from './PasswordReset'
import { resetPassword } from '../Actions'
export const validate = (values) => {
const errors = {}
if (!values.email) {
errors.email = 'E-mail cannot be empty.'
} else if (!/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = 'Invalid e-mail.'
}
return errors
}
export default connect(null, { resetPassword })(
reduxForm(
{ form: 'passwordReset',
validate
})(PasswordReset))
Output from test is following:
PasswordResetContainer › should render only one ReduxForm
expect(received).toEqual(expected)
Expected value to equal:
1
Received:
2
Edit (partial solution found):
When I changed wrapper.find('ReduxForm')
into wrapper.find('ReduxForm>Hoc>ReduxForm') it started to work.
Why do I need to do such a magic?
A fix is on library mods to create but if the forms are identical, one quick way to get around the issue is to call first() after find so that
wrapper.find('ReduxForm')
looks like:
wrapper.find('ReduxForm').first()

Vue <template> in a .vue file with Lodash

In my .vue file within my template section I have:
<a v-bind:href="'javascript:artist(\'' + _.escape(artist) + '\')'">
which is using the Lodash function _.escape. This generates a string of errors the first of which is:
[Vue warn]: Property or method "_" is not defined on the instance but referenced during
render.
However in the same file in the script section of the component I am happily and successfully using a range of Lodash functions.
This is a Laravel app and in my app.js file I have this code:
require('./bootstrap');
window.Vue = require('vue');
import VueRouter from 'vue-router';
window.Vue.use(VueRouter);
import lodash from 'lodash';
Object.defineProperty(Vue.prototype, '$lodash', { value: lodash });
import SearchHome from './components/search.vue';
const routes = [
{
path: '/',
components: {
searchHome: SearchHome
}
},
]
const router = new VueRouter({ routes })
const app = new Vue({ router }).$mount('#app')
Can anyone please help me?
Try to use a computed value instead. This will improve readability.
Avoid complex operation in a binding.
<a :href="artistLink">
And in the script
import _ from 'lodash'
export default {
computed: {
artistLink () {
return 'javascript:artist(\'' + _.escape(this.artist) + '\')'
}
}
}

Vue.js how to use npm plugins

I have tried multiple different plugins with my Vue.js cli webpack projects and I am getting the same problem with all of them, namely that once I have included a plugin, I am unable to use it.
As an example. I have tried to use the plugin at this link. https://www.npmjs.com/package/vue-sessionstorage
Here is my main.js file
import Vue from 'vue'
import router from './router'
import VueMaterial from 'vue-material'
import { store } from './store'
import 'vue-material/dist/vue-material.css'
import 'vue-style-loader'
import VueSessionStorage from 'vue-sessionstorage'
import App from './App'
Vue.use(VueMaterial, VueSessionStorage);
Vue.config.productionTip = false;
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: { App },
});
I have run npm install --save vue-sessionstorage
As you can see, I have also imported VueSessionStorage
However, when I try to use it like this
methods: {
login: function () {
console.log("Login clicked");
this.$session.set('username','simon')
console.log(this.$session.get('username'));
},
register: function () {
console.log(this.$session.get('username'));
}
}
I get the error
vue.esm.js?65d7:563 TypeError: Cannot read property 'set' of undefined
at VueComponent.login (Login.vue?2ddf:35)
at boundFn (vue.esm.js?65d7:179)
at Proxy.invoker (vue.esm.js?65d7:1821)
at Proxy.Vue.$emit (vue.esm.js?65d7:2331)
at click (mdButton.vue?3bf8:38)
at HTMLButtonElement.invoker (vue.esm.js?65d7:1821)
handleError # vue.esm.js?65d7:563
Vue.$emit # vue.esm.js?65d7:2333
click # mdButton.vue?3bf8:38
invoker # vue.esm.js?65d7:1821
Vue.use does not permit multiple plugins to be initialized at once like that. Initialize them as two separate calls:
Vue.use(VueMaterial);
Vue.use(VueSessionStorage);

Redux + storybook throws warning about changing store on the fly even with module.hot implemtended

I'm using storybook and I want to add redux as decorator.
Whe running storybook, I got warning in console:
<Provider> does not support changing `store` on the fly. It is most likely that you see this error because you updated to Redux 2.x and React Redux 2.x which no longer hot reload reducers automatically. See https://github.com/reactjs/react-redux/releases/tag/v2.0.0 for the migration instructions.
It's my code for config storybook:
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import React from 'react';
import { configure, storiesOf } from '#storybook/react';
import { Provider as ReduxProvider } from 'react-redux';
import forEach from 'lodash/forEach';
import unset from 'lodash/unset';
import Provider from 'components/Provider';
import initStore from 'utils/initStore';
import messages from '../lang/en.json';
const req = require.context('../components', true, /_stories\.js$/);
const ProviderDecorator = (storyFn) => {
const TheProvider = Provider(() => storyFn());
return (
<ReduxProvider store={initStore()}>
<TheProvider key={Math.random()} now={1499149917064} locale="en" messages={messages} />
</ReduxProvider>
);
}
function loadStories() {
req.keys().forEach((filename) => {
const data = req(filename);
if (data.Component !== undefined && data.name !== undefined && data.stories !== undefined) {
const Component = data.Component;
const stories = storiesOf(data.name, module);
stories.addDecorator(ProviderDecorator);
let decorator = data.stories.__decorator;
if (data.stories.__decorator !== undefined) {
stories.addDecorator((storyFn) => data.stories.__decorator(storyFn()));
}
forEach(data.stories, (el, key) => {
if (key.indexOf('__') !== 0) {
stories.add(key, () => (
<Component {...el} />
));
}
});
} else {
console.error(`Missing test data for ${filename}!`)
}
});
}
configure(loadStories, module);
and initStore file:
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunkMiddleware from 'redux-thunk';
import { persistStore, autoRehydrate } from 'redux-persist';
import reducers from 'containers/redux/reducers';
export default () => {
const store = createStore(
reducers,
{},
composeWithDevTools(applyMiddleware(thunkMiddleware), autoRehydrate()),
);
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../containers/redux/reducers', () => {
const nextReducers = require('../containers/redux/reducers'); // eslint-disable-line global-require
store.replaceReducer(nextReducers);
});
}
persistStore(store);
return store;
};
So as you can see I followed instructions from link in warning. What have I done wrong and how can I remove this warning? I know it won't show on production server, but it's pretty annoying in dev mode. :/
The reason this is happening has to do with the way Storybook hot-loads.
When you change your story, that module is hot-loaded, meaning that the code inside it is executed again.
Since you're using a store creator function and not a store instance from another module, the actual store object that is being passed to ReduxProvider on hot-load is new every time.
However, the React tree that is re-constructed is for the most part identical, meaning that the ReduxProvider instance is re-rendered with new props instead of being re-created.
Essentially, this is changing its store on the fly.
The solve is to make sure that ReduxProvider instance is new, too, on hot-load. This is easily solved by passing it a unique key prop, e.g.:
const ProviderDecorator = (storyFn) => {
const TheProvider = Provider(() => storyFn());
return (
<ReduxProvider key={Math.random()} store={initStore()}>
<TheProvider key={Math.random()} now={1499149917064} locale="en" messages={messages} />
</ReduxProvider>
);
}
From React Keys:
Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity.

Resources