I use WebStorm and I have this plugin: https://github.com/idok/react-templates-plugin
Having it installed in my WebStorm I can type for example rcls and immediately have:
import React, {
Component,
PropTypes,
} from 'react';
class LocalizedText extends Component {
render() {
return (
<div></div>
);
}
}
LocalizedText.propTypes = {};
LocalizedText.defaultProps = {};
export default LocalizedText;
I wonder if it is possible to find some file on my computer and make some changes (new lines and so on) manually?
Sorry if it's a silly question but I can't find the answer in google.
Related
I built a simple Vue component that wraps the Trix editor. I'm trying to write tests for it, but Trix doesn't seem to mount properly and isn't generating a toolbar element like it does in the browser. I'm using Jest test runner.
TrixEdit.vue
<template>
<div ref="trix">
<trix-editor></trix-editor>
</div>
</template>
<script>
import 'trix'
export default {
mounted() {
let el = this.$refs.trix.getElementsByTagName('trix-editor')[0]
// HACK: change the URL field in the link dialog to allow non-urls
let toolbar = this.$refs.trix.getElementsByTagName('trix-toolbar')[0]
toolbar.querySelector('[type=url]').type = 'text'
// insert content
el.editor.insertHTML(this.value)
el.addEventListener('trix-change', e => {
this.$emit('input', e.target.innerHTML)
})
}
}
</script>
TrixEdit.spec.js
import { mount, shallowMount, createLocalVue } from '#vue/test-utils'
import TrixEdit from '#/components/TrixEdit.vue'
const localVue = createLocalVue()
localVue.config.ignoredElements = ['trix-editor']
describe('TrixEdit', () => {
describe('value prop', () => {
it('renders text when value is set', () => {
const wrapper = mount(TrixEdit, {
localVue,
propsData: {
value: 'This is a test'
}
})
expect(wrapper.emitted().input).toEqual('This is a test')
})
})
})
The expect() fails with the following error
Expected value to equal:
"This is a test"
Received:
undefined
at Object.toEqual (tests/unit/TrixEdit.spec.js:19:39)
Why is Trix not initializing in my test?
trix-editor is not mounting mainly because MutationObserver is not supported in JSDOM 11, and attachToDocument was not used. There were several other bugs in the test described below.
GitHub demo w/issues fixed
Missing MutationObserver and window.getSelection
Vue CLI 3.7.0 uses JSDOM 11, which doesn't support MutationObserver, needed by the Custom Elements polyfill to trigger the connectedCallback. That lifecycle hook normally invokes trix-editor's initialization, which would create the trix-toolbar element that your test is trying to query.
Solution 1: In your test, import mutationobserver-shim before TrixEdit.vue, and stub window.getSelection (called by trix and currently not supported by JSDOM):
import 'mutationobserver-shim' // <-- order important
import TrixEdit from '#/components/TrixEdit.vue'
window.getSelection = () => ({})
Solution 2: Do the above in a Jest setup script, configured by setupTestFrameworkScriptFile:
Add the following property to the config object in jest.config.js (or jest in package.json):
setupTestFrameworkScriptFile: '<rootDir>/jest-setup.js',
Add the following code to <rootDir>/jest-setup.js:
import 'mutationobserver-shim'
window.getSelection = () => ({})
Missing attachToDocument
#vue/test-utils does not attach elements to the document by default, so trix-editor does not catch the connectedCallback, which is needed for its initialization.
Solution: Use the attachToDocument option when mounting TrixEdit:
const wrapper = mount(TrixEdit, {
//...
attachToDocument: true, // <-- needed for trix-editor
})
Premature reference to trix-editor's editor
TrixEdit incorrectly assumes that trix-editor is immediately initialized upon mounting, but initialization isn't guaranteed until it fires the trix-initialize event, so accessing trix-editor's internal editor could result in an undefined reference.
Solution: Add an event handler for the trix-initialize event that invokes the initialization code previously in mounted():
<template>
<trix-editor #trix-initialize="onInit" />
</template>
<script>
export default {
methods: {
onInit(e) {
/* initialization code */
}
}
}
</script>
Value set before change listener
The initialization code adds a trix-change-event listener after the value has already been set, missing the event trigger. I assume the intention was to also detect the first initial value setting in order to re-emit it as an input event.
Solution 1: Add event listener first:
<script>
export default {
methods: {
onInit(e) {
//...
el.addEventListener('trix-change', /*...*/)
/* set editor value */
}
}
}
</script>
Solution 2: Use v-on:trix-change="..." (or #trix-change) in the template, which would remove the setup-order problem above:
<template>
<trix-editor #trix-change="onChange" />
</template>
<script>
export default {
methods: {
onChange(e) {
this.$emit('input', e.target.innerHTML)
},
onInit(e) {
//...
/* set editor value */
}
}
}
</script>
Value setting causes error
The initialization code sets the editor's value with the following code, which causes an error in test:
el.editor.insertHTML(this.value) // causes `document.createRange is not a function`
Solution: Use trix-editor's value-accessor, which performs the equivalent action while avoiding this error:
el.value = this.value
I can confirm the problem lies in the not-so-ideal polymer polyfill included inside trix lib. I did an experiment to force apply the polyfill, then I can reproduce the same error TypeError: Cannot read property 'querySelector' of undefined even inside chrome browser env.
Further investigation narrows it down to the MutationObserver behavior difference, but still haven't got to the bottom.
Way to reproduce:
TrixEdit.vue
<template>
<div ref="trix">
<trix-editor></trix-editor>
</div>
</template>
<script>
// force apply polymer polyfill
delete window.customElements;
document.registerElement = undefined;
import "trix";
//...
</script>
I am contributing to a project which is built with React (with webpack) running in Electron. When executing unit tests with Jest, it fails with the error TypeError: Cannot read property 'on' of undefined (and works fine when not testing, eg. run with Electron).
The code:
import React, { Component } from 'react';
import { ipcRenderer } from 'electron';
// some more imports
class Setup extends Component {
constructor(props) {
super(props);
this.state = {
// some state
};
ipcRenderer.on('open-file-reply', this.someMethod); // << fails on this line
}
// more class stuff
}
It took me a few days but finally, I found this answer in this great blog post. Quote:
Jest is called from Node and doesn't run test code through Webpack.
Instead, we have to use Jest's mocking functions to replace the import
with a stub file.
Jest has a helper method called moduleNameMapper [object<string, string>] . From jest documentation:
A map from regular expressions to module names that allow to stub out
resources, like images or styles with a single module.
It should be added in your package.json root object like this:
{
"name": "My awesome app",
"jest": {
"moduleNameMapper": {
"electron": "<rootDir>/src/components/tests/mock/electron.js"
}
}
}
and the mock file itself (/src/components/tests/mock/electron.js):
export const ipcRenderer = {
on: jest.fn()
};
This way you can stub other electron modules and methods (like remote which is shown in the blog above).
Another way is creating an electron.js file in __mocks__ in your root folder.
The electron.js should look something like
export const ipcRenderer = {
on: jest.fn(),
};
You can read more at https://jestjs.io/docs/en/manual-mocks#mocking-node-modules
Wondering what is the best practices to use django with React when i18n needed.
Currently I'm loading javascript_catalog on global scope.
all the translations controlled by django i18n.
From react components I'm using gettext django javascript catalog function to translate all the necessary texts.
For localization i'm also using django i10n support provided by javascript_catalog.
anyone have better practices for this using i18n in both django and react
I do not claim this is best practice but it works for me. Separating the frontend and backend a bit.
Think about it, what part translation is related to ? UI/UX right ?
Therefore, why have it on the backend, why not just have it in your react project ?
Steps: install i18next for react:
npm install react-i18next#legacy i18next --save
Notice, you will not get a > v9 but this tutorial :
https://react.i18next.com/legacy-v9/step-by-step-guide
is still valid,
step 1:
create translation folder in your src folder like this:
-src
-translations
-ar
transilationsAR.js
-en
transilationEN.js
- i18n.js
- App.js
The way I do it, is manually to insure amazing User experience.
This code will turn any keywords From ENGLISH-ENGLISH to any language:
data_pre.py
en_en= {"kw": "kw"}
en_kw = []
for kw in en_en:
en_kw.append(kw)
# translate the list of english kw to desired language via google translate
ar_kw = """ [en_to_desired_langauge] """
ar_kw = ar_kw.replace("،", ",")
ar_kw = eval(ar_kw)
en_ar = dict()
for i in range(0, len(ar_kw)):
en_ar[en_kw[i]] = ar_kw[i]
# en_ar key words are in en_ar variable.
transilationEN.js : Here we will have for example ENGLISH-ENGLISH keywords dictionary,
there are some tools help you fetch all key words, phrases from your website.
export const TRANSLATIONS_EN = {
'Hello': 'Hello',
}
transilationAR.js, here we have new dictionary out of data preprocessing.
export const TRANSLATIONS_AR = {
'Hello': 'مرحبا',
}
run
npm install --save i18next-browser-languagedetector
i18n.js
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import {TRANSLATIONS_AR } from "./ar/translationsAR";
import { TRANSLATIONS_EN } from "./en/translationsEN";
// the translations
// (tip move them in a JSON file and import them)
const resources = {
en: {
translation: TRANSLATIONS_EN
},
ar: {
translation: TRANSLATIONS_AR
},
};
i18n
.use(initReactI18next)
.use(LanguageDetector)
.init({
resources,
lng:[ "en", 'ar'],
keySeparator: false,
interpolation: {
escapeValue: false
},
react: {
useSuspense: false
}
});
export default i18n;
App.js
import React, { Component } from "react";
import { withTranslation } from 'react-i18next';
import i18n from "./translations/i18n";
class App extends Component {
handleChangeLangToAR = () => {
i18n.changeLanguage("ar")
};
handleChangeLangToEN = () => {
i18n.changeLanguage("en")
};
render() {
return (
<SomeComponent
{...this.props}
handleChangeLangToAR={() => this.handleChangeLangToAR()}
handleChangeLangToEN={ () => this.handleChangeLangToEN()}
/>
);
}
}
export default (withTranslation()(App));
now in someComponent.js we have acess to t() via props, which can be use to translate any keywords, phrases on our website.
someComponent.js
import React from "react";
class someComponent extends React.Component {
render() {
const { handleChangeLangToEN, handleChangeLangToAR, t} = this.props;
return (
<h1>{t('Hello')}</h1>
)
}
};
export default someComponent();
handleChangeLangToEN: can be set to onClick on a button to switch site language to English.
handleChangeLangToAR : can be set to onClick a button to switch site language to Arabic.
Both sould be in layout component, so we do not have to pass them every where in our project.
for example:
<Button OnClick={ () => handleChangeLangToEN }> English </Button>
Or if we have another component we want to translate, simply we export the component with WithTranslation , then we have access to t():
anotherComponent.js
import React from "react";
import { withTranslation } from 'react-i18next';
class anotherComponent extends React.Component {
render() {
const {t} = this.props;
return (
<h1>{t('Hello')}</h1>
)
}
};
export default (withTransilation()anotherComponent)
if you are connecting your props using redux store an still would like to use withTransilation(), do not get confused, you do it like this.
const mapStateToProps = state => {
return {
isAuthenticated: state.auth.token !== null
};
};
const mapDispatchToProps = dispatch => {
return {
onTryAutoSignup: () => dispatch(actions.authCheckState())
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(withTranslation()(App));
'''
I have looked into react-intl for suggestions but it doesn't leave any explicit documentation for enzyme.
This is how I have been trying to write my tests.
import {IntlProvider} from 'react-intl';
const intlProvider = new IntlProvider({locale: 'en'}, {});
const intl = intlProvider.getChildContext();
const customMessage = shallow(<CustomMessage />, { options: { context: intl } });
But I keep getting the error
Invariant Violation: [React Intl] Could not find required intl object. needs to exist in the component ancestry.
I looked into their repo and they seems to have made it work with 'react-addons-test-utils'.
Am I doing something wrong?
I've posted an answer to a similar question:
Injecting react-intl object into mounted Enzyme components for testing
You would be able to import { shallowWithIntl } from 'intl-helper' and then use shallowWithIntl() instead of Enzyme's shallow().
I got it working by using
const customMessage = shallow(<CustomMessage />, { context: intl });
instead.
Thats how I achieve the things:
import React from 'react';
import StandardFilterIntl, {StandardFilter} from 'bundles/components/Filter/StandardFilter';
import {mountWithIntl} from 'enzyme-react-intl';
const FilterComponent = mountWithIntl(<StandardFilterIntl {...standardFilterProps} />);
FilterComponent.find(StandardFilter).state()
I'm new to Mocha and I am trying to use it to test a simple React component. The test would pass if the react component doesn't have any CSS styling but throws a syntax error if the tag within the React component contains any className:
Testing.react.js
import React from 'react';
export default class Testing extends React.Component {
render() {
return (
<section>
<form>
<input type="text" />
</form>
</section>
);
}
}
testing.jsx
import {
React,
sinon,
assert,
expect,
TestUtils
} from '../../test_helper';
import TestingSample from '../../../app/components/Testing.react.js';
describe('TestingSample component', function(){
before('render and locate element', function(){
var renderedComponent = TestUtils.renderIntoDocument(
<TestingSample />
);
var inputComponent = TestUtils.findRenderedDOMComponentWithTag(
renderedComponent, 'input'
);
this.inputElement = inputComponent.getDOMNode();
});
it('<input> should be of type "text"', function () {
assert(this.inputElement.getAttribute('type') === 'text');
});
})
The test would pass:
> mocha --opts ./test/javascripts/mocha.opts --compilers js:babel/register --recursive test/javascripts/**/*.jsx
TestSample component
✓ <input> should be of type "text"
1 passing (44ms)
after I added the className inside of the input tag an error shows up:
import React from 'react';
import testingStyle from '../../scss/components/landing/testing.scss';
export default class Testing extends React.Component {
render() {
return (
<section>
<form>
<input type="text" className="testingStyle.color" placeholder="Where would you like to dine" />
</form>
</section>
);
}
}
Test result:
SyntaxError: /Users/../../../Documents/project/app/scss/components/landing/testing.scss: Unexpected token (1:0)
> 1 | .color {
| ^
2 | color: red;
3 | }
I've searched online but no luck so far. Am I missing something? Please help me out or point me to the right direction would be greatly appreciated.
I'm currently using:
Node Express Server
React
React-router
Webpack
Babel
Mocha
Chai
Sinon
Sinon-Chai
There is a babel/register style hook to ignore style imports:
https://www.npmjs.com/package/ignore-styles
Install it:
npm install --save-dev ignore-styles
Run tests without styles:
mocha --require ignore-styles
you can use a css compilers run mocha, the compiler js as follow:
css-dnt-compiler.js
function donothing() {
return null;
}
require.extensions['.css'] = donothing;
require.extensions['.less'] = donothing;
require.extensions['.scss'] = donothing;
// ..etc
and run the mocha command like this:
mocha --compilers js:babel-core/register,css:css-dnt-compiler.js --recursive
My same answer as here, this is what I used to get working on Babel 6
package.json
"scripts": {
"test": "mocha --compilers js:babel-core/register
--require ./tools/testHelper.js 'src/**/*-spec.#(js|jsx)'",
tools/testHelper.js
// Prevent mocha from interpreting CSS #import files
function noop() {
return null;
}
require.extensions['.css'] = noop;
This enables you to have your tests inside your src folder alongside your components. You can add as many extensions as you would like with require.extensions.
Since you're using webpack, use null-loader to load null when webpack encounters a required CSS/LESS/SASS/etc file in your components. Install via npm and then update your webpack config to include the loader:
{
test: /(\.css|\.less|.\scss)$/,
loader: 'null-loader'
}
Obviously this will prevent you from loading CSS in your actual application, so you'll want to have a separate webpack config for your test bundle that uses this loader.
For those looking how to handle this in jest - you just add a handler for style files:
// package.json
{
"jest": {
"moduleNameMapper": {
"\\.(css|less|scss|sass)$": "<rootDir>/__mocks__/styleMock.js"
}
}
}
// __mocks__/styleMock.js
module.exports = {};
More here.
None of these solutions worked for me, as I'm using mocha-webpack, and it doesn't accept the "--compilers" switch. I implemented the ignore-styles package, as described in the most popular answer, but it seemed inert, with no difference in my Istanbul coverage report (.less files still being tested).
The problem is the .less loader that I was using in my webpack.config.test.js file. Simply swapping less-loader for null-loader fixed my problem.
module: {
rules: [
{
test: /\.less$/,
use: ['null-loader']
}
]
}
For me, this is by far the simplest solution, and targets my testing configuration directly, rather than having to alter/add to the package.json scripts, or worse, add new .js files.
One simple way is to import 'ignore-styles'; in your test classes..
The code below works without any dependencies. Just add it to the top of the tests.
var Module = require('module');
var originalRequire = Module.prototype.require;
Module.prototype.require = function () {
if (arguments[0] && arguments[0].endsWith(".css"))
return;
return originalRequire.apply(this, arguments);
};
Although very old, this question is still relevant, so let me throw in another solution.
Use pirates, a package to add hooks to require() - if you use Babel, you already have it.
Example code:
// .test-init.js
const { addHook } = require('pirates');
const IGNORE_EXTENSIONS = ['.scss', '.svg', '.css'];
addHook((code, filename) => '', { exts: IGNORE_EXTENSIONS });
This way you can call mocha like so: mocha --require .test-init.js [whatever other parameters you use]
This is straightforward, elegant and unlike ignore-styles it doesn't imply you are ignoring styles only. Also, this is easily extendable if you need to apply some more trickery to your tests like mocking entire modules.