//index.mjs
import { createStore } from 'redux'
import todoApp from './reducers'
const store = createStore(todoApp)
import {
addTodo,
toggleTodo,
setVisibilityFilter,
VisibilityFilters
} from './actions'
// Log the initial state
console.log(store.getState())
// Every time the state changes, log it
// Note that subscribe() returns a function for unregistering the listener
const unsubscribe = store.subscribe(() =>
console.log(store.getState())
)
// Dispatch some actions
store.dispatch(addTodo('Learn about actions'))
store.dispatch(addTodo('Learn about reducers'))
store.dispatch(addTodo('Learn about store'))
store.dispatch(toggleTodo(0))
store.dispatch(toggleTodo(1))
store.dispatch(setVisibilityFilter(VisibilityFilters.SHOW_COMPLETED))
// Stop listening to state updates
unsubscribe()
//reducers.mjs
import { combineReducers } from 'redux'
import {
ADD_TODO,
TOGGLE_TODO,
SET_VISIBILITY_FILTER,
VisibilityFilters
} from './actions'
const { SHOW_ALL } = VisibilityFilter
function visibilityFilter(state = SHOW_ALL, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return action.filter
default:
return state
}
}
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
case TOGGLE_TODO:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
})
}
return todo
})
default:
return state
}
}
const todoApp = combineReducers({
visibilityFilter,
todos
})
export default todoApp
// actions.mjs
/*
* action types
*/
export const ADD_TODO = 'ADD_TODO'
export const TOGGLE_TODO = 'TOGGLE_TODO'
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER'
/*
* other constants
*/
export const VisibilityFilters = {
SHOW_ALL: 'SHOW_ALL',
SHOW_COMPLETED: 'SHOW_COMPLETED',
SHOW_ACTIVE: 'SHOW_ACTIVE'
}
/*
* action creators
*/
export function addTodo(text) {
return { type: ADD_TODO, text }
}
export function toggleTodo(index) {
return { type: TOGGLE_TODO, index }
}
export function setVisibilityFilter(filter) {
return { type: SET_VISIBILITY_FILTER, filter }
}
Edit- added code
I am working through the Redux Basics tutorial from the Redux docs, and am having trouble getting import to work properly.
I currently have 3 files for my todo-list app:
actions.mjs
reducers.mjs
index.mjs
I have done an npm init -y, and npm install --save redux. I copy and pasted the source code directly from the Redux docs for all 3 files.
With the command: node --experimental-modules index, I get the error:
SyntaxError: The requested module 'redux' does not provide an export named 'combineReducers'
I would expect similar error messages for other named exports of Redux...
I have had success with refactoring back to CommonJS using require, module.exports, .js file extensions, and the command: node index.js
Related
I encountered a error when using NestJS. The console shows 0 error first and then crahsed with the Error: Cannot find module './'. This is similar to the
Error:Cannot find module '../module_name'.
However, for this one, it shows './'. And I tried to delete the node_module and the dist folder and rerun the npm install that was usually used to solve the similar people.
The full error message is:
[6:32:11 PM] Starting compilation in watch mode...
[6:32:14 PM] Found 0 errors. Watching for file changes.
Error: Cannot find module './'
Require stack:
- C:\Users\Vibrant\Desktop\inventory_demo\dist\client\client.service.js
- C:\Users\Vibrant\Desktop\inventory_demo\dist\client\client.controller.js
- C:\Users\Vibrant\Desktop\inventory_demo\dist\client\client.module.js
- C:\Users\Vibrant\Desktop\inventory_demo\dist\app.module.js
- C:\Users\Vibrant\Desktop\inventory_demo\dist\main.js
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
at Function.Module._load (node:internal/modules/cjs/loader:778:27)
at Module.require (node:internal/modules/cjs/loader:1005:19)
at require (node:internal/modules/cjs/helpers:102:18)
at Object.<anonymous> (C:\Users\Vibrant\Desktop\inventory_demo\src\client\client.service.ts:3:1)
at Module._compile (node:internal/modules/cjs/loader:1101:14)
The client.service.js:
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientService = void 0;
const common_1 = require("#nestjs/common");
const client_1 = require("./");
let ClientService = class ClientService {
async client(clientWhereUniqueInput) {
return client_1.default.client.findUnique({
where: clientWhereUniqueInput,
});
}
async clients(params) {
const { skip, take, cursor, where } = params;
return client_1.default.client.findMany({
skip,
take,
cursor,
where,
});
}
async createClient(data) {
return client_1.default.client.create({ data });
}
async deleteClient(where) {
return client_1.default.client.delete({ where });
}
async getClientByID(id) {
return await client_1.default.client.findUnique({
where: { client_id: Number(id) },
});
}
async updateClient(params) {
const { where, data } = params;
return client_1.default.client.update({ where, data });
}
};
ClientService = __decorate([
(0, common_1.Injectable)()
], ClientService);
exports.ClientService = ClientService;
//# sourceMappingURL=client.service.js.map
I have two ts files has client in the name:
First one is called client.ts which is a prism database client:
import { PrismaClient } from '#prisma/client';
interface CustomNodeJsGlobal extends NodeJS.Global {
prisma: PrismaClient;
}
// Prevent multiple instances of Prisma Client in development
declare const global: CustomNodeJsGlobal;
const prisma = global.prisma || new PrismaClient();
if (process.env.NODE_ENV === 'development') global.prisma = prisma;
export default prisma;
The second one is a model called client, it only imports the basic nestjs modules I think.
The client module.ts
import { Module } from '#nestjs/common';
import { ClientController } from './client.controller';
import { ClientService } from './client.service';
#Module({
controllers: [ClientController],
providers: [ClientService]
})
export class ClientModule {}
The client controller(haven't start it yet):
import { Controller } from '#nestjs/common';
#Controller('client')
export class ClientController {}
and the client service:
import { Injectable } from '#nestjs/common';
import { Client, Prisma } from '#prisma/client';
import prisma from 'src/client';
#Injectable()
export class ClientService {
// The service to return a single client
async client(
clientWhereUniqueInput: Prisma.ClientWhereUniqueInput,
): Promise<Client> {
return prisma.client.findUnique({
where: clientWhereUniqueInput,
});
}
// The service to return a list of clients
async clients(params: {
skip?: number;
take?: number;
cursor?: Prisma.ClientWhereUniqueInput;
where?: Prisma.ClientWhereInput;
}): Promise<Client[]> {
const { skip, take, cursor, where } = params;
return prisma.client.findMany({
skip,
take,
cursor,
where,
});
}
// The service to create a client
async createClient(data: Prisma.ClientCreateInput): Promise<Client> {
return prisma.client.create({ data });
}
// The service to delete a client
async deleteClient(where: Prisma.ClientWhereUniqueInput): Promise<Client> {
return prisma.client.delete({ where });
}
// The service to find an client by id
async getClientByID(id: string) {
return await prisma.client.findUnique({
where: { client_id: Number(id) },
});
}
// The service to update a client
async updateClient(params: {
where: Prisma.ClientWhereUniqueInput;
data: Prisma.ClientUpdateInput;
}): Promise<Client> {
const { where, data } = params;
return prisma.client.update({ where, data });
}
// End of class
}
The problem is I used a model called client.
The solution is to rename it to clients since NestJS itself uses the name client. After the name modification, I will need to delete the whole dist folder and run npm rebuild.
I am trying to use React and Easybase (database). I'm having some issues however.
This is in the SolanaSignature.tsx file.
import { useWallet } from '#solana/wallet-adapter-react';
import bs58 from 'bs58';
import React, { FC, useCallback } from 'react';
import ReactDOM from 'react-dom';
import { sign } from 'tweetnacl';
import AddUser from './mainstorage';
export const SignMessageButton : FC = () => {
const { publicKey, signMessage } = useWallet();
const onClick = useCallback(async () => {
try {
if (!publicKey) throw new Error('Wallet not connected!');
if (!signMessage) throw new Error('Wallet does not support message signing! Please use a wallet such as Phantom or Solflare! NOTE: Some Ledgers wallets are not supported!');
const message = new TextEncoder().encode('Omega Protocol - Signature verification for Bold Badgers.');
const signature = await signMessage(message);
if (!sign.detached.verify(message, signature, publicKey.toBytes())) throw new Error('Invalid signature!');
//alert(`Message signature: ${bs58.encode(signature)}`);
AddUser();
} catch (error: any) {
alert(`Signing failed: ${error?.message}`);
}
}, [publicKey, signMessage]);
return signMessage ? (<button className="wallet-adapter-button wallet-adapter-button-trigger shine" onClick={onClick} disabled={!publicKey}>Verify</button>) : null;
};
and then the mainstorage file:
import { useEffect } from 'react';
import { useEasybase } from 'easybase-react';
const AddUser = () => {
const { db } = useEasybase();
useEffect(() => {
db('OMEGABB').insert({ walletid: "test", discordid: "test", signature: "test", valid: false, lastvalid: new Date() }).one()
.then(() => console.log("Success!"));
}, [])
return (
{/* ... */}
);
}
export default AddUser;
What is happening however when I click the button is that it comes up with a warning: Hooks can only be called inside the body of a function component.
This does work in the initial index file (aka the parent file) but does not work here. Right now this is only a dummy/test but trying to get it writing to the database.
Thanks!
As per React's documentation:
Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns.
Currently, you're attempting to call a hook inside the onClick handler - AddUser is a custom hook since it also uses hooks and the better name for it should be useAddUser.
I suggest to make some improvements by returning a function from your custom hook that you can call to add a new user, e.g.:
export const useAddUser = () => {
const {db} = useEasybase()
const addUser = React.useCallback(() => {
db('OMEGABB')
.insert(/*...*/)
.then(/*...*/)
.catch(/*...*/)
}, [db])
return {
addUser,
/*...*/
}
}
Then, you can use useAddUser in the following way:
const {useAddUser} from './mainstorage'
const SignMessageButton: FC = () => {
const {publicKey, signMessage} = useWallet()
const {addUser} = useAddUser();
const onClick = React.useCallback(
async () => {
try {
// ...
addUser()
} catch (error) {/*...*/}
},
[publicKey, signMessage, addUser]
)
/*...*/
}
Testing libs...always fun. I am using next-i18next within my NextJS project. We are using the useTranslation hook with namespaces.
When I run my test there is a warning:
console.warn
react-i18next:: You will need to pass in an i18next instance by using initReactI18next
> 33 | const { t } = useTranslation(['common', 'account']);
| ^
I have tried the setup from the react-i18next test examples without success. I have tried this suggestion too.
as well as just trying to mock useTranslation without success.
Is there a more straightforward solution to avoid this warning? The test passes FWIW...
test('feature displays error', async () => {
const { findByTestId, findByRole } = render(
<I18nextProvider i18n={i18n}>
<InviteCollectEmails onSubmit={jest.fn()} />
</I18nextProvider>,
{
query: {
orgId: 666,
},
}
);
const submitBtn = await findByRole('button', {
name: 'account:organization.invite.copyLink',
});
fireEvent.click(submitBtn);
await findByTestId('loader');
const alert = await findByRole('alert');
within(alert).getByText('failed attempt');
});
Last, is there a way to have the translated plain text be the outcome, instead of the namespaced: account:account:organization.invite.copyLink?
Use the following snippet before the describe block OR in beforeEach() to mock the needful.
jest.mock("react-i18next", () => ({
useTranslation: () => ({ t: key => key }),
}));
Hope this helps. Peace.
use this for replace render function.
import { render, screen } from '#testing-library/react'
import DarkModeToggleBtn from '../../components/layout/DarkModeToggleBtn'
import { appWithTranslation } from 'next-i18next'
import { NextRouter } from 'next/router'
jest.mock('react-i18next', () => ({
I18nextProvider: jest.fn(),
__esmodule: true,
}))
const createProps = (locale = 'en', router: Partial<NextRouter> = {}) => ({
pageProps: {
_nextI18Next: {
initialLocale: locale,
userConfig: {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
},
},
},
} as any,
router: {
locale: locale,
route: '/',
...router,
},
} as any)
const Component = appWithTranslation(() => <DarkModeToggleBtn />)
const defaultRenderProps = createProps()
const renderComponent = (props = defaultRenderProps) => render(
<Component {...props} />
)
describe('', () => {
it('', () => {
renderComponent()
expect(screen.getByRole("button")).toHaveTextContent("")
})
})
I used a little bit more sophisticated approach than mocking to ensure all the functions work the same both in testing and production environment.
First, I create a testing environment:
// testing/env.ts
import i18next, { i18n } from "i18next";
import JSDomEnvironment from "jest-environment-jsdom";
import { initReactI18next } from "react-i18next";
declare global {
var i18nInstance: i18n;
}
export default class extends JSDomEnvironment {
async setup() {
await super.setup();
/* The important part start */
const i18nInstance = i18next.createInstance();
await i18nInstance.use(initReactI18next).init({
lng: "cimode",
resources: {},
});
this.global.i18nInstance = i18nInstance;
/* The important part end */
}
}
I add this environment in jest.config.ts:
// jest.config.ts
export default {
// ...
testEnvironment: "testing/env.ts",
};
Sample component:
// component.tsx
import { useTranslation } from "next-i18next";
export const Component = () => {
const { t } = useTranslation();
return <div>{t('foo')}</div>
}
And later on I use it in tests:
// component.test.tsx
import { setI18n } from "react-i18next";
import { create, act, ReactTestRenderer } from "react-test-renderer";
import { Component } from "./component";
it("renders Component", () => {
/* The important part start */
setI18n(global.i18nInstance);
/* The important part end */
let root: ReactTestRenderer;
act(() => {
root = create(<Component />);
});
expect(root.toJSON()).toMatchSnapshot();
});
I figured out how to make the tests work with an instance of i18next using the renderHook function and the useTranslation hook from react-i18next based on the previous answers and some research.
This is the Home component I wanted to test:
import { useTranslation } from 'next-i18next';
const Home = () => {
const { t } = useTranslation("");
return (
<main>
<div>
<h1> {t("welcome", {ns: 'home'})}</h1>
</div>
</main>
)
};
export default Home;
First, we need to create a setup file for jest so we can start an i18n instance and import the translations to the configuration. test/setup.ts
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import homeES from '#/public/locales/es/home.json';
import homeEN from '#/public/locales/en/home.json';
i18n.use(initReactI18next).init({
lng: "es",
resources: {
en: {
home: homeEN,
},
es: {
home: homeES,
}
},
fallbackLng: "es",
debug: false,
});
export default i18n;
Then we add the setup file to our jest.config.js:
setupFilesAfterEnv: ["<rootDir>/test/setup.ts"]
Now we can try our tests using the I18nextProvider and the useTranslation hook:
import '#testing-library/jest-dom/extend-expect';
import { cleanup, render, renderHook } from '#testing-library/react';
import { act } from 'react-dom/test-utils';
import { I18nextProvider, useTranslation } from 'react-i18next';
import Home from '.';
describe("Index page", (): void => {
afterEach(cleanup);
it("should render properly in Spanish", (): void => {
const t = renderHook(() => useTranslation());
const component = render(
<I18nextProvider i18n={t.result.current.i18n}>
<Home / >
</I18nextProvider>
);
expect(component.getByText("Bienvenido a Pocky")).toBeInTheDocument();
});
it("should render properly in English", (): void => {
const t = renderHook(() => useTranslation());
act(() => {
t.result.current.i18n.changeLanguage("en");
});
const component = render(
<I18nextProvider i18n={t.result.current.i18n}>
<Home/>
</I18nextProvider>
);
expect(component.getByText("Welcome to Pocky")).toBeInTheDocument();
});
});
Here we used the I18nextProvider and send the i18n instance using the useTranslation hook. after that the translations were loaded without problems in the Home component.
We can also change the selected language running the changeLanguage() function and test the other translations.
I am using vue-i18n plugin for my Vue3(typescript) application. Below is my setup function in component code
Home.vue
import {useI18n} from 'vue-i18n'
setup() {
const {t} = useI18n()
return {
t
}
}
Main.ts
import { createI18n } from 'vue-i18n'
import en from './assets/translations/english.json'
import dutch from './assets/translations/dutch.json'
// internationalization configurations
const i18n = createI18n({
messages: {
en: en,
dutch: dutch
},
fallbackLocale: 'en',
locale: 'en'
})
// Create app
const app = createApp(App)
app.use(store)
app.use(router)
app.use(i18n)
app.mount('#app')
Code works and compiles fine. But jest test cases fails for the component when it's mounting
Spec file
import { mount, VueWrapper } from '#vue/test-utils'
import Home from '#/views/Home.vue'
import Threat from '#/components/Threat.vue'
// Test case for Threats Component
let wrapper: VueWrapper<any>
beforeEach(() => {
wrapper = mount(Home)
// eslint-disable-next-line #typescript-eslint/no-empty-function
jest.spyOn(console, 'warn').mockImplementation(() => { });
});
describe('Home.vue', () => {
//child component 'Home' existance check
it("Check Home component exists in Threats", () => {
expect(wrapper.findComponent(Home).exists()).toBe(true)
})
// Threat level list existance check
it("Check all 5 threat levels are listed", () => {
expect(wrapper.findAll('.threat-level .level-wrapper label')).toHaveLength(5)
})
})
Below is the error
Please help me to resolve this.
The vue-18n plugin should be installed on the wrapper during mount with the global.plugins option:
import { mount } from '#vue/test-utils'
import { createI18n } from 'vue-i18n'
import Home from '#/components/Home.vue'
describe('Home.vue', () => {
it('i18n', () => {
const i18n = createI18n({
// vue-i18n options here ...
})
const wrapper = mount(Home, {
global: {
plugins: [i18n]
}
})
expect(wrapper.vm.t).toBeTruthy()
})
})
GitHub demo
You can also define the plugin globally in the setup/init file:
import { config } from '#vue/test-utils'
import { createI18n } from 'vue-i18n'
const i18n = createI18n({
// vue-i18n options here ...
})
config.global.plugins = [i18n]
config.global.mocks.$t = (key) => key
I have some problems with my universal react app runing with saga. I'm rendering react on server. One of my react component executes redux action that should be catched by saga listener on server.
Here is abstract example
// *Header.js*
class Header extends React.PureComponent {
componentWillMount() {
this.props.doAction()
}
....
}
export default connect(null, {doAction})(Header)
// *actions.js*
function doAction() {
return {
type: "action"
}
}
// *saga.js*
function* doAsyncAction(action) {
console.log(action);
}
function* watchAction() {
yield takeEvery("action", doAsyncAction);
}
export default [
watchAction(),
];
// *sagas.js* --> root saga
import 'regenerator-runtime/runtime';
import saga from './saga';
import anotherSaga from './anotherSaga'
export default function* rootSaga() {
yield all([].concat(saga).concat(anotherSaga));
}
// *configureStore.js*
const sagaMiddleware = createSagaMiddleware();
const middleware = applyMiddleware(sagaMiddleware);
...
sagaMiddleware.run(require('./sagas').default);
And after first run node process - it runs and give me console log, but
when I just refresh browser and function doAsyncAction is never executed
Please help, what I'm doing wrong ?
You need to change this:
function doAction() {
return {
type: "action"
}
}
to this:
const mapDispatchtoProps = (dispatch) => {
return {
doAction: () => dispatch({type: "action"})
}
}
export default connect(null, mapDispatchtoProps)(Header)
Client.js setup below for saga middleware:
const sagaMiddleware = createSagaMiddleware()
const createStoreWithMiddleware = applyMiddleware(sagaMiddleware)(createStore)
let store = createStoreWithMiddleware(rootReducers)
sagaMiddleware.run(rootSaga)
The above is implemented where ever you are implementing your store.