sort order import in react using cra - reactjs

I am trying to update my project's configuration to sort the import order. I'm using create-react-app, and have been following the instructions in this article. Here's what I've done so far:
Run yarn add eslint-plugin-import -D.
Added a .eslintrc.js in src folder of my application.
Added the following configuration as mentioned in the article:
module.exports = {
extends: "react-app",
plugins: ["eslint-plugin-import"],
"import/order": [
"error",
{
groups: ["builtin", "external", "internal"],
pathGroups: [
{
pattern: "react",
group: "external",
position: "before",
},
],
pathGroupsExcludedImportTypes: ["react"],
"newlines-between": "always",
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
};
I've written the following sample component and changed the order of import statements to check if this is working, but when I save the order is not being updated:
Sample.js
import { PropTypes } from "prop-types";
import React from "react";
const Sample = () => <div>Hello</div>;
export default Sample;
Expected after saving
Sample.js
import React from "react";
import { PropTypes } from "prop-types";
const Sample = () => <div>Hello</div>;
export default Sample;
I also tried simple-import-sort, but I don't know how to configure it. How can I configure my project so that import statements are automatically kept in order?

in pathGroups change react to be built, not external:
"pathGroups": [
{
"group": "builtin",
"pattern": "react",
"position": "before"
},
{
"group": "external",
"pattern": "#/**",
"position": "before"
}]

Related

TS8006: 'import type' declarations can only be used in TypeScript files

Building a React NextJS and rollup bumps into the following error:
rollup.config.js:
import json from '#rollup/plugin-json';
import typescript from '#rollup/plugin-typescript';
import ts from "rollup-plugin-ts";
import jsx from 'acorn-jsx';
import tsConfig from './tsconfig.json';
const config = [
{
input: "index.ts",
output: [{ file: "build/index.js", sourcemap: true }],
acornInjectPlugins: [jsx()],
plugins: [
typescript(
{
sourceMap: tsConfig.compilerOptions.sourceMap
}
),
json()
]
},
{
input: "index.ts",
output: [{ file: "build/index.d.ts", "format": "es" }],
acornInjectPlugins: [jsx()],
plugins: [
ts(
{
compilerOptions: {
baseUrl: tsConfig.compilerOptions.baseUrl
}
}
),
json()
]
},
]
export default config;
2: import clsx from "clsx";
3: import { sortBy } from "lodash";
4: import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
^
5: import { Direction } from "react-beautiful-dnd/src/types";
6: import makeStyles from "#mui/styles/makeStyles";
...and 2 other occurrences
[!] (plugin Typescript) TS8006: 'import type' declarations can only be used in TypeScript files.
node_modules/react-beautiful-dnd/src/types.js (2:1)
2 import type { BoxModel, Rect, Position } from 'css-box-model';
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
in VSCode:
Make sure you have the extension Flow Language Support installed.
Go to extensions
Type: Flow Language Support
Install the Flow Language Support extension
Go to extensions and disable TypeScript and JavaScript Language
Go to extensions
Type: #builtin TypeScript and JavaScript Language Features
Disable the extension
Click on Reload Required

css module support using react Rolllup

I'm working on building out a react package (not app) and have run into my introduction to using rollup which, as I understand it, the equivalent to using webpack for react app development.
As I'm moving my code over I've run into a snag where I can't seem to work out the configuration to allow for css/scss module support, e.g.,
import React from "react";
import styles from "./Button.css"; <--- TS2307: Cannot find module './Button.css' or its corresponding type declarations.
my configuration looks like this:
import resolve from "#rollup/plugin-node-resolve";
import commonjs from "#rollup/plugin-commonjs";
import typescript from "#rollup/plugin-typescript";
import postcss from "rollup-plugin-postcss";
import dts from "rollup-plugin-dts";
const packageJson = require("./package.json");
export default [
{
input: "./src/index.ts",
output: [
{
file: packageJson.main,
format: "cjs",
sourcemap: true
},
{
file: packageJson.module,
format: "esm",
sourcemap: true
}
],
plugins: [
resolve(),
postcss({
extract: false,
modules: true,
use: ['sass'],
}),
commonjs(),
typescript({ tsconfig: "./tsconfig.json" })
]
},
{
input: "dist/esm/types/index.d.ts",
output: [{ file: "dist/index.d.ts", format: "esm" }],
plugins: [dts()],
external: [/\.(css|less|scss)$/]
}
];
but I can't get passed the error:
TS2307: Cannot find module './Button.css' or its corresponding type declarations.
my web research has found some attempts at solving this, but nothing has worked. I can drop the css directly on the component:
import React from "react";
import "./Button.css";
But the assignment doesn't work. Any ideas on solution?

How do I unit test amcharts using jest with react and typescript?

I have reproduced the compilation error that I came across while working on a project using Jest with amCharts. Apparently, Jest cannot compile anything to do with amchart for unit testing.
Error
/core.js:8
export { System, system } from "./.internal/core/System";
^^^^^^
SyntaxError: Unexpected token 'export'
1 | import { useEffect, useRef } from "react";
> 2 | import * as am4core from "#amcharts/amcharts4/core";
| ^
3 | import * as am4charts from "#amcharts/amcharts4/charts";
4 |
5 | const data = [
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1350:14)
at Object.<anonymous> (src/App.tsx:2:1)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 1.067 s
Ran all test suites.
Jest.config.ts
module.exports = {
roots: ["<rootDir>/src"],
collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}", "!src/**/*.d.ts"],
setupFiles: ["react-app-polyfill/jsdom"],
testMatch: [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}",
],
testEnvironment: "jsdom",
testRunner:
"/home/xeonrazr/Playground/amcharts-jest-err/node_modules/jest-circus/runner.js",
transform: {
"^.+\\.(js|jsx|mjs|cjs|ts|tsx)$": "<rootDir>/config/jest/babelTransform.js",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)":
"<rootDir>/config/jest/fileTransform.js",
},
transformIgnorePatterns: [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$",
"^.+\\.module\\.(css|sass|scss)$",
],
modulePaths: [],
moduleNameMapper: {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy",
},
moduleFileExtensions: [
"web.js",
"js",
"web.ts",
"ts",
"web.tsx",
"tsx",
"json",
"web.jsx",
"jsx",
"node",
],
watchPlugins: [
"jest-watch-typeahead/filename",
"jest-watch-typeahead/testname",
],
resetMocks: true,
};
App.tsx
import { useEffect, useRef } from "react";
import * as am4core from "#amcharts/amcharts4/core";
import * as am4charts from "#amcharts/amcharts4/charts";
const data = [
{
country: "Lithuania",
litres: 501.9,
},
{
country: "Czech Republic",
litres: 301.9,
},
{
country: "Ireland",
litres: 201.1,
},
{
country: "Germany",
litres: 165.8,
},
{
country: "Australia",
litres: 139.9,
},
{
country: "Austria",
litres: 128.3,
},
{
country: "UK",
litres: 99,
},
{
country: "Belgium",
litres: 60,
},
{
country: "The Netherlands",
litres: 50,
},
];
function App() {
const chartRef = useRef(am4core.create("chartdiv", am4charts.PieChart));
useEffect(() => {
let series = chartRef.current.series.push(new am4charts.PieSeries());
series.dataFields.value = "litres";
series.dataFields.category = "country";
chartRef.current.data = data;
chartRef.current.legend = new am4charts.Legend();
}, []);
return (
<div className="App">
<div
data-testid="chartdiv"
style={{ height: "600px", width: "100%" }}
id="chartdiv"
></div>
</div>
);
}
export default App;
App.test.tsx
import { render } from "#testing-library/react";
import App from "./App";
test("renders learn react link", () => {
const { getByTestId } = render(<App />);
const chartEl = getByTestId("chartdiv");
expect(chartEl).toBeInTheDocument();
});
Repo Link
Jest currently doesn't understand either import or export. It looks like you followed common setup docs for your jest config so you're probably using babel and transpiling your code from using modules to using commonjs, but you're not transpiling your dependencies:
transformIgnorePatterns: [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$", // <-- do not transform node_modules
"^.+\\.module\\.(css|sass|scss)$",
],
But, what's causing your problem is that one of your exports (amCharts) needs to be transformed in order to make those import/export statements compliant with the commonjs format that jest is expecting.
Your easiest fix is probably to edit the transformIgnorePatterns:
transformIgnorePatterns: [
//Add other modules here that ship ESM that Jest doesn't like
'node_modules/(?!#amcharts)',
"^.+\\.module\\.(css|sass|scss)$",
],
So we're saying "go ahead and don't transform anything in node modules unless it matches #amcharts. If you get more dependencies that need to be transformed, then you can add it to that regex.
For a different solution, if you like experimental features, then you can try turning on Jest's experimental support for esm: https://jestjs.io/docs/ecmascript-modules.

How to load environment variable in tests with Next.js?

I'm trying to run a simple test with JavaScript as below.
import React from 'react';
import Customization from 'components/onboarding/customization';
import '#testing-library/jest-dom';
import { render, screen, fireEvent } from '#testing-library/react';
describe('customization render', () => {
it('should render the Hero page with no issue', () => {
render(<Customization />);
const heading = screen.getByText(
/All the Moodmap at one place!/i
);
expect(heading).toBeInTheDocument();
});
it("should call onCLick method on click", () => {
const mockOnClick = jest.fn()
const {container} = render(<Customization />);
const button = getByTestId(container, 'alreadyDownloaded');
fireEvent.click(button);
expect(mockOnClick).toHaveBeenCalledTimes(1)
// const mockOnClick = jest.fn()
// const utils = render(<Customization onClick={mockOnClick} />)
// fireEvent.click(screen.getByText(/already downloaded ⟶/i))
// expect(mockOnClick).toHaveBeenCalledTimes(1)
})
});
When running the tests I'm getting this error
No google analytics trackingId defined
8 | debug: process.env.NODE_ENV !== 'production',
9 | plugins: [
> 10 | googleAnalyticsPlugin({
| ^
11 | trackingId: process.env.NEXT_PUBLIC_GA_TRACKING_ID,
12 | }),
How do I make this error go away - surely it shouldn't require Google Analytics code given the above, it's not in production when running the test?
Update
So I need to make sure the .env file is being loaded!
In my package.json I've got this Jest setup:
"jest": {
"testMatch": [
"**/?(*.)(spec|test).?(m)js?(x)"
],
"moduleNameMapper": {
"\\.(css|less|scss)$": "identity-obj-proxy"
},
"moduleDirectories": [
"node_modules",
"src"
],
"rootDir": "src",
"moduleFileExtensions": [
"js",
"jsx",
"mjs"
],
"transform": {
"^.+\\.m?jsx?$": "babel-jest"
},
"coverageThreshold": {
"global": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": -10
}
}
},
updated code to use jest.setup - can't get env to load
So
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import "#testing-library/jest-dom";
configure({
adapter: new Adapter()
});
module.exports = {
testMatch: [
"**/?(*.)(spec|test).?(m)js?(x)"
],
moduleNameMapper: {
"\\.(css|less|scss)$": "identity-obj-proxy"
},
moduleDirectories: [
"node_modules",
"src"
],
rootDir: "src",
moduleFileExtensions: [
"js",
"jsx",
"mjs"
],
transform: {
"^.+\\.m?jsx?$": "babel-jest"
},
coverageThreshold: {
"global": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": -10
}
},
setupFiles: ["../<rootDir>/.config.env.test"]
};
The environment variable files is here:
process.env.NEXT_PUBLIC_GA_TRACKING_ID=xxx
And this is the code that is not loading the environment variables properly.
import Analytics from 'analytics';
import googleAnalyticsPlugin from '#analytics/google-analytics';
import Router from 'next/router';
// Initialize analytics and plugins
// Documentation: https://getanalytics.io
const analytics = Analytics({
debug: process.env.NODE_ENV !== 'production',
plugins: [
googleAnalyticsPlugin({
trackingId: process.env.NEXT_PUBLIC_GA_TRACKING_ID,
}),
],
});
During your tests you can leverage loadEnvConfig from #next/env to make sure your environment variables are loaded the same way Next.js does.
First setup a .env.test to be used during the tests.
NEXT_PUBLIC_GA_TRACKING_ID=ga-test-id
Next, create a Jest global setup file if you don't have one yet, and reference it in your jest.config.js.
// jest.config.js
module.exports = {
//...
setupFilesAfterEnv: ['./jest.setup.js'],
};
Then add the following code into your Jest global setup file.
// jest.setup.js
import { loadEnvConfig } from '#next/env'
loadEnvConfig(process.cwd())
This message means that the trackingId is not defined. As you can see it read from the process.env. You need to create this file in the root of your project and call it .env. Note that the dot is at the beginning of the filename. The content of the file should be as follow:
NEXT_PUBLIC_GA_TRACKING_ID=insert-key-here
If your env file is not being read by jest you can do the following:
// In jest.config.js :
module.exports = {
....
setupFiles: ["<rootDir>/test/setup-tests.ts"]
}
// The file test/test-setup.ts:
import dotenv from 'dotenv';
dotenv.config({path: './config.env.test'});
You can also check this article for more details.

TSLint - Preventing error: The key is not sorted alphabetically

I'm doing a test app with Ionic2 / Cordova / Typescript / Angular.
I'm using tslint 5.6.0.
I'm using the following module:
https://www.npmjs.com/package/tslint
Focusing on just one file...
when linting the following file:
import { NgModule, ErrorHandler } from "#angular/core";
import { BrowserModule } from "#angular/platform-browser";
import { IonicApp, IonicModule, IonicErrorHandler } from "ionic-angular";
import { MyApp } from "./app.component";
import { AboutPage } from "../pages/about/about";
import { ContactPage } from "../pages/contact/contact";
import { HomePage } from "../pages/home/home";
import { TabsPage } from "../pages/tabs/tabs";
import { StatusBar } from "#ionic-native/status-bar";
import { SplashScreen } from "#ionic-native/splash-screen";
#NgModule( {
declarations: [
MyApp,
AboutPage,
ContactPage,
HomePage,
TabsPage,
],
imports: [
BrowserModule,
IonicModule.forRoot( MyApp ),
],
bootstrap: [ IonicApp ],
entryComponents: [
MyApp,
AboutPage,
ContactPage,
HomePage,
TabsPage,
],
providers: [
StatusBar,
SplashScreen,
{ provide: ErrorHandler, useClass: IonicErrorHandler },
],
})
export class AppModule { }
I get:
The key 'bootstrap' is not sorted alphabetically
RuleFailurePosition { position: 790, lineAndCharacter: { line: 25, character: 4 } }
RuleFailurePosition { position: 799, lineAndCharacter: { line: 25, character: 13 } }
I'm using the following options:
{
"extends": "tslint:recommended",
"rules": {
"no-duplicate-variable": true,
"max-line-length": {
"options": [120]
},
"ordered-imports": false,
"new-parens": true,
"no-arg": true,
"no-bitwise": true,
"no-conditional-assignment": true,
"no-consecutive-blank-lines": false,
"no-console": {
"options": [
"debug",
"info",
"log",
"time",
"timeEnd",
"trace"
]
}
},
"jsRules": {
"max-line-length": {
"options": [120]
}
}
}
What option do I need to configure on TSLint to prevent showing up this error?
The rule failing here seems to be object-literal-sort-keys.
You should be able to disable it in the rules section of your config file by adding:
"object-literal-sort-keys": false
You can find all the tslint rules here.
For anyone coming here who is doing a migration to TypeScript from javascript, or who simply has a mixed codebase of javascript + typescriptm you may to define this rule inside 'jsRules' as well, i.e. to get rid of this error, when you having console statements defined inside javascript (not typescript files).
//tslint.json
{
"extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"],
"rules": {
"object-literal-sort-keys": false //Disable for typescript
},
"jsRules": {
"object-literal-sort-keys": false //Disable for javascript
}
}

Resources