tl;dr
How to make SWC compile .js (not .jsx) files which contains React jsx for mocha tests?
I'm setting up Mocha + SWC (replacing a current Mocha + Babel setup), and am facing an issue where SWC won't compile jsx content inside .js files. It will only do so for .jsx files.
I've prepared a minimal Github repo showcasing the issue.
I've tried getting help from the SWC GitHub repo, but the help I got was unhelpful and my bug report has been closed, so I guess it won't get much attention now.
.swcrc
{
"$schema": "https://json.schemastore.org/swcrc",
"jsc": {
"parser": {
"syntax": "ecmascript",
"jsx": true,
"dynamicImport": false,
"privateMethod": true,
"functionBind": false,
"exportDefaultFrom": true,
"exportNamespaceFrom": false,
"decorators": true,
"decoratorsBeforeExport": true,
"topLevelAwait": false,
"importMeta": false
},
"transform": {
"legacyDecorator": true,
"react": {
"pragma": "React.createElement",
"pragmaFrag": "React.Fragment",
"throwIfNamespace": true,
"development": false,
"useBuiltins": false
},
"optimizer": {
"globals": {
"vars": {
"__DEBUG__": "true"
}
}
}
},
"target": "es5",
"loose": false,
"externalHelpers": false,
// Requires v1.2.50 or upper and requires target to be es2016 or upper.
"keepClassNames": false
},
"module": {
"type": "commonjs"
},
"minify": false
}
package.json
{
"name": "swc-js-extension-fails-with-jsx-content",
"version": "1.0.0",
"description": "SWC not parsing jsx in js files",
"author": {
"name": "Yair Even-Or",
"email": "vsync.design#gmail.com"
},
"private": false,
"type": "module",
"dependencies": {
"#babel/runtime": "7.17.8",
"#swc-node/register": "1.5.5",
"#swc/cli": "0.1.59",
"#swc/core": "1.3.27",
"#wojtekmaj/enzyme-adapter-react-17": "0.8.0",
"jsdom": "^21.0.0",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"#babel/cli": "7.19.3",
"#babel/core": "7.20.2",
"#babel/eslint-parser": "7.19.1",
"#babel/plugin-proposal-class-properties": "7.12.1",
"#babel/plugin-proposal-decorators": "7.12.12",
"#babel/plugin-proposal-export-default-from": "7.12.1",
"#babel/plugin-proposal-function-bind": "7.12.1",
"#babel/plugin-proposal-nullish-coalescing-operator": "7.12.1",
"#babel/plugin-proposal-optional-chaining": "7.12.7",
"#babel/plugin-transform-runtime": "7.19.6",
"#babel/preset-env": "7.20.2",
"#babel/preset-react": "7.18.6",
"#babel/register": "7.18.9",
"chai": "4.3.7",
"enzyme": "3.11.0",
"mocha": "9.2.2"
},
"browserslist": {
"modern": [
"last 1 chrome version",
"last 1 firefox version"
],
"ssr": [
"node 14"
]
},
"scripts": {
"test": "mocha \"src/**/*.test.js\""
}
}
jsconfig
{
"compilerOptions": {
"baseUrl": ".",
"target": "esnext",
"moduleResolution": "Node",
"experimentalDecorators": true,
"jsx": "react-jsx"
}
}
With Babel - .js files extensions works:
.mocharc.json - "require": ["#babel/register", "setup.js"],
With SWC - does not compile .js-extension mocha tests (with jsx syntax)
.mocharc.json - "require": ["#swc-node/register", "setup.js"],
Related
I have a very simple React/TypeScript application, and I'm trying to learn how to implement testing. I'm using React Testing Library and Jest. It's a very simple product page, and I just want to test that the words "Welcome to our product page" have rendered.
When I run the test, I get this error message: The error below may be caused by using the wrong test environment, see https://jestjs.io/docs/configuration#testenvironment-string. Consider using the "jsdom" test environment. ReferenceError: document is not defined.
I went through all the solutions in similar questions on Stack Overflow, but nothing is working. I tried adding
/**
* #jest-environment jsdom
*/
to the top of the test file, but that just produces a different error message: ReferenceError: global is not defined.
I'd appreciate any help. Below is my code:
ProductPage.test.tsx
import React from "react";
import { render, screen } from "#testing-library/react";
import ProductPage from "../ProductPage";
describe("<ProductPage />", () => {
test("should display the product page", () => {
render(<ProductPage />);
expect(
screen.getByText(/Welcome to our product page/)
).toBeInTheDocument();
});
});
jest.config.js
module.exports = {
roots: ["<rootDir>/src"],
transform: {
"^.+\\.tsx?$": "ts-jest",
"^.+\\.svg$": "<rootDir>/svgTransform.js",
"^.+\\.css$": "<rootDir>/cssTransform.js"
},
setupFilesAfterEnv: [
"#testing-library/jest-dom/extend-expect"
],
testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"]
};
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"allowSyntheticDefaultImports": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}
package.json
{
"name": "product-page",
"version": "0.1.0",
"private": true,
"dependencies": {
"#apollo/client": "^3.4.17",
"#babel/core": "^7.16.0",
"#babel/preset-env": "^7.16.4",
"#babel/preset-typescript": "^7.16.0",
"#emotion/react": "^11.6.0",
"#emotion/styled": "^11.6.0",
"#mui/material": "^5.1.1",
"#mui/system": "^5.1.1",
"#testing-library/jest-dom": "^5.11.4",
"#testing-library/react": "^11.1.0",
"#testing-library/user-event": "^12.1.10",
"#types/jest": "^27.0.2",
"#types/node": "^16.11.7",
"#types/react": "^17.0.35",
"#types/react-dom": "^17.0.11",
"babel-jest": "^27.3.1",
"graphql": "^16.0.1",
"jest": "^27.3.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"ts-jest": "^27.0.7",
"typescript": "^4.4.4",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "jest",
"test:watch": "jest --watch",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"ts-node": "^10.4.0"
}
}
In order to use jsdom you need to add
testEnvironment: 'jsdom',
to your jest.config.js
Edit: You might need to add it as a dependency also.
Add testEnvironment: 'jsdom' to jest.config.js. This resolved the jsdom error.
Add jest-environment-jsdom as a dev dependency (adding jsdom did not help for whatever reason). This resolved the global error.
I'm trying to make a simple test to get to know unit tests using mocha.
Folder Structure
node_modules
package.json
package-lock.json
testA.ts
testA.spec.ts
tsconfig.json
tsconfig.json
{
"compilerOptions": {
"target": "ES2019",
"module": "commonjs",
"rootDir": "./",
"moduleResolution": "node",
"allowJs": false,
"declaration": false,
"outDir": "./dist",
"esModuleInterop": false,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitAny": false,
"noImplicitThis": true,
"alwaysStrict": true,
"skipLibCheck": true
},
"exclude": [
"node_modules"
]
}
package.json
{
"name": "unittest",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"test": "mocha",
"build": "rm -rf dist && tsc"
},
"author": "",
"license": "ISC",
"devDependencies": {
"#types/chai": "^4.2.22",
"#types/jest": "^27.0.3",
"#types/mocha": "^9.0.0",
"#types/sinon": "^10.0.6",
"chai": "^4.3.4",
"mocha": "^9.1.3",
"nyc": "^15.1.0",
"sinon": "^12.0.1",
"typescript": "^4.5.2",
"ts-node": "^10.4.0"
},
"mocha": {
"check-leaks": true,
"globals": [
"crypto"
],
"recursive": true,
"spec": [
"./*.ts"
]
}
}
testA.spec.ts
import * as chai from 'chai'
const expect = chai.expect
describe('First Test', () => {
it('should run the test', () => {
const a = 12
expect(a).to.be.equal(12)
})
})
When I run npm test, I get the follow error.
/home/user/dev/unitTest/node_modules/#babel/core/src/config/files/index-browser.ts:1
import type { Handler } from "gensync";
^^^^^^
SyntaxError: Cannot use import statement outside a module
Tried everything I could find searching on the internet but still unable to solve this one.
I found the solution. Inside package.json I added the require for mocha:
"devDependencies":{...},
"mocha": {
"require": [
"support/ts-node-register.js"
],
ts-node-register.js
const tsNode = require('ts-node');
tsNode.register({
files: true,
});
I am currently working with VueJS and TypeScript 2.9.1. I am creating a library and converted it to typescript later on.
When building the lib with vue-cli the typescript linter says the following error message:
WARNING Compiled with 1 warnings 5:57:15 PM
error: Parsing error: Unexpected token
36 |
37 | export default class Graph {
> 38 | private _nodes: GraphNodeList = {}
| ^
39 | private _edges: EdgeList = {}
40 |
41 | layout: Layout | undefined at src/Graph.ts:38:11:
If I delete the 'private' keyword the errors are gone. But I know that the private keyword is allowed in typescript. They also write it like this in the documentation.
Does anyone know why this happens? Would be cool to use private variables in the future.
tslint.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"node",
"jest"
],
"paths": {
"#/*": [
"src/*"
]
},
"lib": [
"es2017",
"es2015",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
Package.json (reduced)
{
...
"scripts": {
"build": "vue-cli-service build --target lib src/main.ts",
"dev": "vue-cli-service build --mode development --name vue-flowy --watch --target lib src/main.ts",
},
"dependencies": {
"d3": "^5.4.0",
"dagre-d3-renderer": "^0.5.8",
"graphlibrary": "^2.2.0",
"vue-class-component": "^6.0.0",
"vue-property-decorator": "^6.0.0"
},
"devDependencies": {
"#types/debug": "^0.0.30",
"#types/jest": "^22.0.1",
"#vue/cli-plugin-e2e-cypress": "^3.0.0-beta.11",
"#vue/cli-plugin-eslint": "^3.0.0-beta.11",
"#vue/cli-plugin-typescript": "^3.0.0-beta.15",
"#vue/cli-plugin-unit-jest": "^3.0.0-beta.11",
"#vue/cli-service": "^3.0.0-beta.11",
"#vue/eslint-config-prettier": "^3.0.0-beta.11",
"#vue/eslint-config-typescript": "^3.0.0-beta.11",
"#vue/test-utils": "^1.0.0-beta.16",
"debug": "^3.1.0",
"jest": "^22.4.3",
"node-sass": "^4.9.0",
"prettier-eslint-cli": "^4.7.1",
"sass-loader": "^7.0.1",
"ts-jest": "^22.4.6",
"typescript": "^2.8.3",
"vue": "^2.5.16",
"vue-eslint-parser": "^2.0.3"
},
"module": "dist/vue-flowy.es.js",
"repository": {
"type": "git",
"url": "git+https://github.com/Patcher56/vue-flowy.git"
},
"types": "types/index.d.ts",
"files": [
"dist",
"src"
],
"main": "dist/vue-flowy.umd.js",
...
"peerDependencies": {
"vue": "^2.5.16"
},
...
}
vue.config.js
module.exports = {
css: {
extract: false
}
}
build/index.ts
'use strict'
// Template version: 1.2.7
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
module.exports = {
dev: {
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
host: 'localhost',
port: 8080,
autoOpenBrowser: true,
errorOverlay: true,
notifyOnErrors: true,
poll: false,
useEslint: true,
showEslintErrorsInOverlay: true,
devtool: '#source-map',
cacheBusting: true,
cssSourceMap: false
},
bundle: {
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/',
productionSourceMap: false,
devtool: '#source-map',
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
bundleAnalyzerReport: process.env.npm_config_report
},
docs: {
index: path.resolve(__dirname, '../docs/index.html'),
assetsRoot: path.resolve(__dirname, '../docs'),
assetsPublicPath: '',
devtool: '#source-map',
productionSourceMap: false
}
}
Link to whole Repository:
https://github.com/Patcher56/vue-flowy/tree/02c6861e58ffe9ed2f38282e457e7524b8f4cbe8
You can either stick to conventions that says that private variables shouldn't have a leading underscore, or, if you insist on using it, put this in your tslint.json
"variable-name": [true, "allow-leading-underscore"]
Sidenote:
I don't find a explicit vue styleguide for typescript, but the angular equivalent is found here: Angular styleguide
I cleaned up my code a lot and removed some unused dependencies.
I also cleaned up my tslint.json. The problem is gone now.
I think the problem was that there were too many dependencies blocking each other.
Sorry for the time invested by everyone answered this question.
It used to work well but this error suddenly occurred after updating some project dependencies. It comes from a component that render slate.js object (I'm not rendering the editor but the text). I read that this error can be solved by updating babel-preset-react-native, but mine is already the most updated. I've also import babel-polyfill in the entry file.
I've found quite a few issue like this in github but doesn't find a solution for me.
package.json
{
"name": "mobile",
"version": "0.0.1",
"dependencies": {
"antd-mobile": "^2.1.6",
"babel-polyfill": "^6.26.0",
"react": "16.2.0",
"react-native": "^0.49.0",
"react-native-navigation": "^1.1.375",
"slate": "^0.32.4"
},
"devDependencies": {
"babel-jest": "^22.2.2",
"babel-plugin-import": "^1.6.3",
"babel-preset-react-native": "^4.0.0",
"jest": "^22.2.2",
"react-native-dotenv": "^0.1.1",
"react-test-renderer": "^16.2.0"
},
"jest": {
"preset": "react-native"
}
}
{
"presets": ["react-native","react-native-dotenv"],
"plugins": [["import", { "libraryName": "antd-mobile" }]]
}
I use typescript for the app, here's the tsconfig.json
{
"compilerOptions": {
"module": "es2015",
"target": "es2015",
"moduleResolution": "node",
"outDir": "./src",
"experimentalDecorators": true,
"noLib": false,
"declaration": false,
"emitDecoratorMetadata": true,
"lib": ["es6", "dom"],
"types": ["system","node"],
"jsx": "react"
},
"exclude": [
"node_modules"
]
}
I keep getting the following error:
Error Code: TS5055
Cannot write file C:/project/dir/server.js' because it would overwrite input file.
Project: TypeScript/JavaScript Virtual Projects
I even tried changing my entry filename to nodeserver.js and after a while I get the same error:
Error Code: TS5055
Cannot write file C:/project/dir/nodeserver.js' because it would overwrite input file.
Project: TypeScript/JavaScript Virtual Projects
How can I find out what component is trying to overwrite it?
I did notice the file has the BuildAction set to Compile and 'Publish' to true. Could this be the cause? What is the implication of turning off Compile for a .js file? Will I not get any error checking?
Config Files
My tsconfig.json
{
"compileOnSave": true,
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"isolatedModules": false,
"jsx": "react"
},
"exclude": [
"node_modules",
"public",
"server.js",
"Scripts/typings/main",
"Scripts/typings/main.d.ts"
],
"filesGlob": [
"./src/**/*.ts",
"./src/**/*.tsx"
]
}
My package.json
{
"name": "contract-vs-paye-calc-type-script",
"version": "0.0.0",
"description": "ContractVsPayeCalcTypeScript",
"scripts": {
"start": "node nodeserver.js",
"lint": "eslint src"
},
"main": "/src/App.js",
"author": {
"name": "MC",
"email": "admin#admin.com"
},
"dependencies": {
"babel-core": "^6.7.7",
"babel-loader": "^6.2.4",
"express": "3.4.4",
"jade": "*",
"react": "^15.0.1",
"react-dom": "^15.0.1",
"react-hot-loader": "^1.3.0",
"stylus": "*",
"webpack": "^1.13.0",
"webpack-dev-server": "^1.14.1"
},
"module": {
"loaders": [
{
"test": "/\\.ts(x?)$/",
"loader": "babel-loader!ts-loader"
}
]
}
}
It seems that typescript compiler tries to transpile everything, including files that are already javascript. The solution is to add a new field outDir, to the compilerOptions, so it looks like this:
{
...
"compilerOptions": {
...
"outDir": "generated"
}
...
}