I am using absolute imports and
testing a component with Context Provider in a NextJS project.
I have set this up according to jest setup
TEST:
import { render, screen } from 'test-util';
import { Sidebar } from '#/components/Sidebar/Sidebar';
test('if it has a brand image', () => {
render(<Sidebar />);
const brandLogo = screen.getByAltText('logo');
expect(brandLogo).toBeInTheDocument();
});
Here is my test-util.tsx in the root folder.
import React, { FC, ReactElement, ReactNode } from 'react';
import { render, RenderOptions } from '#testing-library/react';
import { AuthProvider } from 'store/auth';
const AllTheProviders: FC = ({ children }) => {
return <AuthProvider>{children}</AuthProvider>;
};
const customRender = (ui: ReactElement, options?: Omit<RenderOptions, 'wrapper'>) =>
render(ui, { wrapper: AllTheProviders, ...options });
export * from '#testing-library/react';
export { customRender as render };
This is my jest.config.js in the root folder
// #ts-nocheck
const nextJest = require('next/jest');
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './',
});
// Add any custom config to be passed to Jest
const customJestConfig = {
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
moduleNameMapper: {
// Handle module aliases (this will be automatically configured for you soon)
'^#/components/(.*)$': '<rootDir>/components/$1',
'^#/pages/(.*)$': '<rootDir>/pages/$1',
'^#/firebase/(.*)$': '<rootDir>/firebase/$1',
'^#/store/(.*)$': '<rootDir>/store/$1',
},
testEnvironment: 'jest-environment-jsdom',
};
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);
Here is jest.setup.js in the root folder
import '#testing-library/jest-dom/extend-expect';
I get this error:
FAIL components/Sidebar/__test__/Sidebar.test.tsx
● Test suite failed to run
Cannot find module 'test-util' from 'components/Sidebar/__test__/Sidebar.test.tsx'
1 | import { Sidebar } from '#/components/Sidebar/Sidebar';
> 2 | import { render } from 'test-util';
| ^
3 |
Here is tsconfig.paths.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#/pages/*": ["./pages/*"],
"#/components/*": ["./components/*"],
"#/features/*": ["./features/*"],
"#/firebase/*": ["./firebase/*"],
"#/store/*": ["./store/*"]
}
}
}
How to solve this issue? I want to use
import { render, screen } from 'test-util';
What works:
import { render, screen } from '../../../test-util';
import { Sidebar } from '#/components/Sidebar/Sidebar';
test('if it has a brand image', () => {
render(<Sidebar />);
const brandLogo = screen.getByAltText('logo');
expect(brandLogo).toBeInTheDocument();
});
I have a similar config, but it works for me.
Try to add moduleDirectories: ["node_modules", "<rootDir>/"]
inside your customJestConfig object.
Related
How can I add Environment Variables in Vite React Project in the vite.config.js file
I wanted to add the proxy_url in the .env file and add it to the environment when deploying.
Please have a look below!
import { defineConfig } from "vite";
import react from "#vitejs/plugin-react";
const proxy_url = "http://localhost:5000/";
export default defineConfig({
plugins: [react()],
server: {
proxy: {
"/api": {
target: proxy_url,
changeOrigin: true,
rewrite: (path) => path.replace(/^/api/, ""),
},
},
},
});
Some blogs and answers on StackOverflow but they were resolving the same issue for Vue.
Those didn't work for me in my Vite-React Project!
This will work. Get a .env file and than make your vite.config.js file like this
import { defineConfig, loadEnv } from 'vite'
import react from '#vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig(({mode})=>{
const env = loadEnv(mode, process.cwd());
return{
plugins: [react()],
build:{
outDir:"./wwwroot/app/", sourcemap:true
},
server: {
port:env.VITE_PORT
}
}
})
This is my .env file. You dont have to install anything extra
VITE_PORT=3000
import { defineConfig, loadEnv } from 'vite'
import vue from '#vitejs/plugin-vue'
export default defineConfig(({mode})=>{
const env = loadEnv(mode, process.cwd());
return{
plugins: [react()],
build:{
outDir:"./wwwroot/app/", sourcemap:true
},
server: {
proxy: {
"^/api": {
target:env.VITE_PORT,
changeOrigin: true,
secure: false,
withCredentials: true,
rewrite: (path) => path.replace(/^\/api/, ``),
},
},
port:4000
}
}
})
Than, you can call it by api
async fetchdata(){
await axios.get(`/api/${mainPage}`,{
}
).then(response=>{})
you can use it in this way:
install "cross-env" package and config vite
import { defineConfig, loadEnv } from 'vite'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '')
return {
define: {
__APP_ENV__: env.APP_ENV,
},
// rest of Vite config
}
}
to use in your code you can do in this way:
import.meta.env.VariableName
update:
according to Vite documentation, environment variables should start with VITE_ prefix to get known
for example in .env file:
VITE_BASE_API_URL=http://localhost:5000
to use it :
import.meta.env.VITE_BASE_API_URL
When i import a .md file , it gave me error, saying that it cannot read this particular .md file syntax,
I know there needs to be some kind of loader for it to parse the import, but when i looked online there was a loader called 'markdown-loader' which was only for marked npm package.
I am using react-markdown package to read md files
/* eslint-disable react/prefer-stateless-function */
import React, { Component } from 'react';
import ReactMarkdown from 'react-markdown';
import AppMarkdown from './posts/sample.md';
// import PropTypes from 'prop-types';
class CardDetails extends Component {
constructor() {
super();
this.state = { markdown: '' };
}
componentDidMount() {
// Get the contents from the Markdown file and put them in the React state, so we can reference it in render() below.
fetch(AppMarkdown)
.then(res => res.text())
.then(text => this.setState({ markdown: text }));
}
render() {
const { markdown } = this.state;
return <ReactMarkdown source={markdown} />;
}
}
CardDetails.propTypes = {};
export default CardDetails;
here's my markdown content sample.md
# React & Markdown App
- Benefits of using React... but...
- Write layout in Markdown!
i could not find package , i looked everywhere, do you know about the loader ?
Thankyou
Try to use raw-loader:
module.exports = {
module: {
rules: [
{
test: /\.md$/,
use: 'raw-loader'
}
]
}
}
I have a simple React application with the following App.js, App.test.js, and utils.js files:
App.js
import React from 'react';
import { randomNameGenerator } from './utils.js';
import './App.css';
function App() {
return (
<div>
{randomNameGenerator()}
</div>
);
}
export default App;
App.test.js
import React from 'react';
import { render } from '#testing-library/react';
import '#testing-library/jest-dom/extend-expect'
import App from './App';
it('allows Jest method mocking', () => {
const { getByText } = render(<App />);
expect(getByText("Craig")).toBeInTheDocument()
});
utils.js
export function randomNameGenerator() {
return Math.floor((Math.random() * 2) + 1) == 1 ? 'Steve' : 'Bill';
}
This is a simple example, but what I'm trying to accomplish is a Jest mock of the randomNameGenerator() function to only return "Craig" for that specific Jest test.
I've followed a wide variety of tutorials/guides, but can't find anything that works - the closest (by "feel") that I've gotten was this (in App.test.js), which had no effect:
jest.doMock('./utils', () => {
const originalUtils = jest.requireActual('./utils');
return {
__esModule: true,
...originalUtils,
randomNameGenerator: jest.fn(() => {
console.log('## Returning mocked typing duration!');
return 'Craig';
}),
};
})
The way it fails is expected:
Unable to find an element with the text: Craig. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
<body>
<div>
<div>
Steve
</div>
</div>
</body>
6 | it('allows Jest method mocking', () => {
7 | const { getByText } = render(<App />);
> 8 | expect(getByText("Craig")).toBeInTheDocument()
| ^
9 | });
You can mock the module by calling jest.mock, and then import it, then inside your tests you call mockImplementation to setup the right return value.
import React from 'react';
import { render } from '#testing-library/react';
import '#testing-library/jest-dom/extend-expect'
import App from './App';
import { randomNameGenerator } from "./utils";
jest.mock('./utils.js', () => ({
randomNameGenerator: jest.fn()
}));
describe('test', () => {
it('allows Jest method mocking 1', () => {
randomNameGenerator.mockImplementation(() => "Craig");
const { getByText } = render(<App />);
expect(getByText("Craig")).toBeInTheDocument()
});
it('allows Jest method mocking 2', () => {
randomNameGenerator.mockImplementation(() => "Not Craig");
const { getByText } = render(<App />);
expect(getByText("Not Craig")).toBeInTheDocument()
});
});
I am trying to import index.ts in a subfolder which has other imports. But I keep getting a typescript error.
full repo: https://github.com/Shavindra/webpack-react-sw
(5,32): error TS2306: File 'C:/../src/reducers/index.ts' is not a module.
I am not quite sure what I am doing wrong here. I am using TS 2.4.1. I've tried restarting the computer/VSCode but nothing seems to work :-|
// ./src/reducers/counter.reducer.ts
export const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
};
// ./src/reducers/index.ts
export * from './counter.reducer';
// ./src/app.ts
import * as React from 'react';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Counter } from './components/counter/counter.component';
import { counterReducer } from './reducers';
const store = createStore(counterReducer);
const rootEl = document.getElementById('root');
const render = () => ReactDOM.render(
<Counter
value={store.getState()}
onIncrement={() => store.dispatch({ type: 'INCREMENT' })}
onDecrement={() => store.dispatch({ type: 'DECREMENT' })}
/>,
rootEl
);
render();
store.subscribe(render);
// tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"sourceMap": true,
"jsx":"react",
"lib": [
"webworker",
"es6",
"scripthost",
"dom"
]
},
"files": [ "node_modules/#types/react-dom/index.d.ts", "node_modules/#types/react/index.d.ts", "typings/file-loader.d.ts" ],
"exclude": [
"typings/browser.d.ts",
"typings/browser",
"node_modules"
]
}
Some ideas are:
reducers is a folder and tsc is trying to search for ./reducers/index.ts
reducers is a file and is not readable by tsc
recuders is a valid file but has a different export system. check UMD, systemjs, commonjs includes
You can include them via:
import counterReducer = require('./recuders');
import * as counterReducer from './recuders';
If you want to include a single module via import { mod } from 'file'; Be sure that you export this function, class or whatever you want in reducers.ts
I hope this ideas helped. let me know!
Can you please post your tsconfig.json to ensure everything is correctly setup?
I am working on upgrading an Angular 1 app to Angular 2 using #angular/upgrade. For the most part this has gone well. I now have an Angular 2 component that works within my Angular 1 app when manually testing.
However, so far I've been unable to successfully unit test the Angular 2 component. My code looks like the following:
app.ts
import "./polyfills";
import "./app.helpers";
import * as angular from "angular";
import "reflect-metadata";
import {UpgradeAdapter, UpgradeAdapterRef} from "#angular/upgrade";
import { NgModule } from "#angular/core";
import {BrowserModule} from "#angular/platform-browser";
import {initRoutes} from "./app.routes";
import {initComponents, components} from "./app.components";
import {initServices, services} from "./app.services";
import {initHttpConfig} from "./app.http-config";
#NgModule({
imports: [BrowserModule],
declarations: [].concat(components),
providers: [].concat(services)
})
class AppModule {}
export const upgradeAdapter = new UpgradeAdapter(AppModule);
const app = angular.module("App", [/*ng1 modules*/]);
initHttpConfig(app);
initRoutes(app);
initComponents(app);
initServices(app);
angular.element(document).ready(() => {
upgradeAdapter.bootstrap(document.body, ["App"]);
});
export default app;
export const ng = angular;
spec-entry.ts
import "./polyfills";
import "zone.js/dist/long-stack-trace-zone";
import "zone.js/dist/proxy.js";
import "zone.js/dist/sync-test";
import "zone.js/dist/jasmine-patch";
import "zone.js/dist/async-test";
import "zone.js/dist/fake-async-test";
import {getTestBed} from "#angular/core/testing";
import {BrowserTestingModule, platformBrowserTesting} from "#angular/platform-browser/testing";
getTestBed().initTestEnvironment(BrowserTestingModule, platformBrowserTesting());
interface WebpackRequire extends NodeRequire {
context(dir: string, includeSubdirs: boolean, matchFiles: RegExp) : any;
}
const wpRequire = require as WebpackRequire;
const testsContext = wpRequire.context(".", true, /\.spec\.ts$/);
testsContext.keys().forEach(testsContext);
my-component.ts
import "../app.ts";
import {
async,
inject,
TestBed,
} from "#angular/core/testing";
import * as moment from "moment";
import {CollegeEvent} from "../models/college-event.model";
import {MyComponent} from "./my.component";
describe("My component", function () {
let fixture;
let component;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [MyComponent],
});
fixture = TestBed.createComponent(MyComponent);
component = fixture.debugElement.componentInstance;
});
it("should not throw an error", () => {
});
});
When running my tests I receive the following error:
1) Error: No provider for TestingCompilerFactory!
Any help would be greatly appreciated.
This may be due to multiple node_modules folders in your client directory. It can be present inside your node_modules folder or in other folder.This happens sometimes when you copy the code or unzip the node_modules folder from outside and another duplicate folder is created.
Angular would have been checking inside node_modules for testing purpose and might have found multiple occurrence for the same.
The main problem is that you need to declare a provider for your all services that are in your component in your beforeEach.
Try the following code in your spec. I'm not sure what TestingCompilerFactory is in your app, but you may have to mock it. Check out the docs.
let comp: MyComponent;
let fixture: ComponentFixture<MyComponent>;
describe("My component", () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ MyComponent ],
providers: [
// DECLARE PROVIDERS HERE
{ provide: TestingCompilerFactory }
]
}).compileComponents()
.then(() => {
fixture = TestBed.createComponent(MyComponent);
comp = fixture.componentInstance;
});
}));
it("should not throw an error", () => {
// not sure how you are storing your errors, this is just an example spec
expect(comp.errors).toEqual([]);
}));
});