I have a NextJS (Typescript) setup with Express . I'm using Moralis, Wagmi and Web3Auth for authentication. The Metamask authentication works, but when I try to setup Web3 Authentication by importing Web3AuthConnector it throws me an error.
My code is like here in the documentation but looks to be an error about CommonJS and ESM which I can't handle. This is the error:
error - Error [ERR_REQUIRE_ESM]: require() of ES Module
C:...\node_modules#web3auth\web3auth-wagmi-connector\node_modules#wagmi\core\dist\index.js
from
C:...\node_modules#web3auth\web3auth-wagmi-connector\dist\web3authWagmiConnector.cjs.js
not supported. Instead change the require of index.js in
C:...\node_modules#web3auth\web3auth-wagmi-connector\dist\web3authWagmiConnector.cjs.js
to a dynamic import() which is available in all CommonJS modules.
I tried to set in package.json "type:module", and in tsconfig: module:"ES6" or "ESNext" but got the same error.
I got the same problem than you and I resolved it by create my own Connector.
I didn't found any other way to do it.
import {
Chain,
Connector,
ConnectorData,
normalizeChainId,
UserRejectedRequestError,
} from "#wagmi/core";
import {
ADAPTER_EVENTS,
ADAPTER_STATUS,
CHAIN_NAMESPACES,
CustomChainConfig,
getChainConfig,
SafeEventEmitterProvider,
WALLET_ADAPTER_TYPE,
WALLET_ADAPTERS,
BaseAdapterConfig,
CONNECTED_EVENT_DATA,
IAdapter,
storageAvailable,
ADAPTER_CATEGORY,
} from "#web3auth/base";
import { Web3AuthCore } from "#web3auth/core";
import { MetamaskAdapter } from "#web3auth/metamask-adapter";
import { OpenloginAdapter } from "#web3auth/openlogin-adapter";
import { TorusWalletAdapter } from "#web3auth/torus-evm-adapter";
import LoginModal, {
getAdapterSocialLogins,
LOGIN_MODAL_EVENTS,
OPENLOGIN_PROVIDERS,
} from "#web3auth/ui";
import {
AdaptersModalConfig,
defaultEvmDappModalConfig,
ModalConfig,
} from "#web3auth/web3auth";
import { Options } from "#web3auth/web3auth-wagmi-connector/dist/types/lib/interfaces";
import { ethers, Signer } from "ethers";
import { getAddress } from "ethers/lib/utils";
import { WalletConnectV1Adapter } from "#web3auth/wallet-connect-v1-adapter";
import QRCodeModal from "#walletconnect/qrcode-modal";
import { ConnectorEvents, defaultChains } from "wagmi";
import EventEmitter from "events";
import { Provider } from "react";
const IS_SERVER = typeof window === "undefined";
const ADAPTER_CACHE_KEY = "Web3Auth-cachedAdapter";
export class Web3AuthConnectorLocal extends Connector {
ready = !IS_SERVER;
readonly id = "web3Auth";
readonly name = "web3Auth";
provider: SafeEventEmitterProvider;
web3AuthInstance?: Web3AuthCore;
isModalOpen = false;
web3AuthOptions: Options;
private loginModal: LoginModal;
private socialLoginAdapter: OpenloginAdapter;
private torusWalletAdapter: TorusWalletAdapter;
private metamaskAdapter: MetamaskAdapter;
private walletConnectV1Adapter: WalletConnectV1Adapter;
private adapters: Record<string, IAdapter<unknown>> = {};
private modalConfig: AdaptersModalConfig = defaultEvmDappModalConfig;
private storage: "sessionStorage" | "localStorage" = "localStorage";
constructor(config: { chains?: Chain[]; options: Options }) {
super(config);
this.web3AuthOptions = config.options;
const chainId = config.options.chainId
? parseInt(config.options.chainId, 16)
: 1;
const chainConfig = this.chains.filter((x) => x.id === chainId);
const defaultChainConfig = getChainConfig(
CHAIN_NAMESPACES.EIP155,
config.options.chainId || "0x1"
);
let finalChainConfig: CustomChainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
...defaultChainConfig,
};
if (chainConfig.length > 0) {
finalChainConfig = {
...finalChainConfig,
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: config.options.chainId || "0x1",
rpcTarget: chainConfig[0].rpcUrls.default,
displayName: chainConfig[0].name,
tickerName: chainConfig[0].nativeCurrency?.name,
ticker: chainConfig[0].nativeCurrency?.symbol,
blockExplorer: chainConfig[0]?.blockExplorers.default?.url,
};
}
this.web3AuthInstance = new Web3AuthCore({
clientId: config.options.clientId,
chainConfig: {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: "0x1",
rpcTarget: "https://rpc.ankr.com/eth", // This is the public RPC we have added, please pass on your own endpoint while creating an app
},
});
this.socialLoginAdapter = new OpenloginAdapter({
adapterSettings: {
...config.options,
},
chainConfig: {
chainId: "0x1",
chainNamespace: CHAIN_NAMESPACES.EIP155,
rpcTarget: "https://rpc.ankr.com/eth",
displayName: "mainnet",
blockExplorer: "https://etherscan.io/",
ticker: "ETH",
tickerName: "Ethereum",
},
});
this.torusWalletAdapter = new TorusWalletAdapter({
adapterSettings: {
buttonPosition: "bottom-left",
},
loginSettings: {
verifier: "google",
},
initParams: {
buildEnv: "testing",
},
chainConfig: {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: "0x1",
rpcTarget: "https://rpc.ankr.com/eth", // This is the mainnet RPC we have added, please pass on your own endpoint while creating an app
displayName: "Ethereum Mainnet",
blockExplorer: "https://etherscan.io/",
ticker: "ETH",
tickerName: "Ethereum",
},
});
this.metamaskAdapter = new MetamaskAdapter({
clientId: config.options.clientId,
});
this.walletConnectV1Adapter = new WalletConnectV1Adapter({
adapterSettings: {
bridge: "https://bridge.walletconnect.org",
qrcodeModal: QRCodeModal,
},
clientId: config.options.clientId,
});
this.web3AuthInstance.configureAdapter(this.socialLoginAdapter);
this.web3AuthInstance.configureAdapter(this.torusWalletAdapter);
this.web3AuthInstance.configureAdapter(this.metamaskAdapter);
this.web3AuthInstance.configureAdapter(this.walletConnectV1Adapter);
this.adapters[this.socialLoginAdapter.name] = this.socialLoginAdapter;
this.adapters[this.torusWalletAdapter.name] = this.torusWalletAdapter;
this.adapters[this.metamaskAdapter.name] = this.metamaskAdapter;
this.adapters[this.walletConnectV1Adapter.name] =
this.walletConnectV1Adapter;
this.loginModal = new LoginModal({
theme: this.options.uiConfig?.theme,
appLogo: this.options.uiConfig?.appLogo || "",
version: "",
adapterListener: this.web3AuthInstance,
displayErrorsOnModal: this.options.displayErrorsOnModal,
});
// this.loginModal.initExternalWalletContainer();
this.subscribeToLoginModalEvents();
}
async connect(): Promise<Required<ConnectorData>> {
this.web3AuthInstance.init();
const adapterEventsPromise = this.subscribeToAdpaterConnectionEvents()
await this.init();
this.loginModal.open();
const elem = document.getElementById("w3a-container");
elem.style.zIndex = "10000000000";
return (await adapterEventsPromise) as Required<ConnectorData>;
}
async subscribeToAdpaterConnectionEvents(): Promise<Required<ConnectorData>> {
return new Promise((resolve, reject) => {
this.web3AuthInstance.once(ADAPTER_EVENTS.CONNECTED, async () => {
console.log(
"Received event connected: ",
this.web3AuthInstance.connectedAdapterName
);
console.log("Requesting Signer");
const signer = await this.getSigner();
const account = await signer.getAddress();
const provider = await this.getProvider();
if (provider.on) {
provider.on("accountsChanged", this.onAccountsChanged.bind(this));
provider.on("chainChanged", this.onChainChanged.bind(this));
provider.on("disconnect", this.onDisconnect.bind(this));
}
return resolve({
account,
chain: {
id: 0,
unsupported: false,
},
provider,
});
});
this.web3AuthInstance.once(ADAPTER_EVENTS.ERRORED, (err: unknown) => {
console.log("error while connecting", err);
return reject(err);
});
});
}
async init(): Promise<void> {
console.log("What is this type: ", typeof this)
console.log("What is this instance: ", this instanceof Web3AuthConnectorLocal)
try {
await this.loginModal.initModal();
const allAdapters = [
...new Set([
...Object.keys(this.modalConfig.adapters || {}),
...Object.keys(this.adapters),
]),
];
const adapterNames = [
"torus-evm",
"metamask",
"openlogin",
"wallet-connect-v1",
];
const hasInAppWallets = true;
// Now, initialize the adapters.
const initPromises = adapterNames.map(async (adapterName) => {
if (!adapterName) return;
try {
const adapter = this.adapters[adapterName];
console.log("Adapter Found: ", adapterName);
console.log("Cached Adapter: ", this.web3AuthInstance.cachedAdapter);
// only initialize a external adapter here if it is a cached adapter.
if (
this.web3AuthInstance.cachedAdapter !== adapterName &&
adapter.type === ADAPTER_CATEGORY.EXTERNAL
) {
console.log(adapterName, " Adapter is not External");
return;
}
// in-app wallets or cached wallet (being connected or already connected) are initialized first.
// if adapter is configured thn only initialize in app or cached adapter.
// external wallets are initialized on INIT_EXTERNAL_WALLET event.
this.subscribeToAdapterEvents(adapter);
if (adapter.status === ADAPTER_STATUS.NOT_READY) {
await adapter.init({
autoConnect: this.web3AuthInstance.cachedAdapter === adapterName,
});
console.log(
"Initializing In Wallet: COMPLETED",
adapter,
adapter.status
);
}
// note: not adding cachedWallet to modal if it is external wallet.
// adding it later if no in-app wallets are available.
if (adapter.type === ADAPTER_CATEGORY.IN_APP) {
this.loginModal.addSocialLogins(
WALLET_ADAPTERS.OPENLOGIN,
getAdapterSocialLogins(
WALLET_ADAPTERS.OPENLOGIN,
this.socialLoginAdapter,
this.options.uiConfig?.loginMethodConfig
),
this.options.uiConfig?.loginMethodsOrder || OPENLOGIN_PROVIDERS
);
}
} catch (error) {
console.log(error, "error while initializing adapter");
}
});
this.web3AuthInstance.status = ADAPTER_STATUS.READY;
await Promise.all(initPromises);
const hasExternalWallets = allAdapters.some((adapterName) => {
return (
this.adapters[adapterName]?.type === ADAPTER_CATEGORY.EXTERNAL &&
this.modalConfig.adapters?.[adapterName].showOnModal
);
});
console.log("Has External Wallets: ", hasExternalWallets);
if (hasExternalWallets) {
this.loginModal.initExternalWalletContainer();
}
if (!hasInAppWallets && hasExternalWallets) {
await this.initExternalWalletAdapters(false, {
showExternalWalletsOnly: true,
});
}
} catch (error) {
console.log("error while connecting", error);
throw new UserRejectedRequestError("Something went wrong");
}
}
async getAccount(): Promise<string> {
const provider = new ethers.providers.Web3Provider(
await this.getProvider()
);
const signer = provider.getSigner();
const account = await signer.getAddress();
return account;
}
async getProvider() {
if (this.provider) {
return this.provider;
}
this.provider = this.web3AuthInstance.provider;
return this.provider;
}
async getSigner(): Promise<Signer> {
console.log("Getting Signer");
const provider = new ethers.providers.Web3Provider(
await this.getProvider()
);
const signer = provider.getSigner();
return signer;
}
async isAuthorized() {
try {
const account = await this.getAccount();
return !!(account && this.provider);
} catch {
return false;
}
}
async getChainId(): Promise<number> {
try {
const networkOptions = this.socialLoginAdapter.chainConfigProxy;
if (typeof networkOptions === "object") {
const chainID = networkOptions.chainId;
if (chainID) {
return normalizeChainId(chainID);
}
}
throw new Error("Chain ID is not defined");
} catch (error) {
console.log("error", error);
throw error;
}
}
async disconnect(): Promise<void> {
await this.web3AuthInstance.logout();
this.provider = null;
}
protected onAccountsChanged(accounts: string[]): void {
if (accounts.length === 0) this.emit("disconnect");
else this.emit("change", { account: getAddress(accounts[0]) });
}
protected onChainChanged(chainId: string | number): void {
const id = normalizeChainId(chainId);
const unsupported = this.isChainUnsupported(id);
this.emit("change", { chain: { id, unsupported } });
}
protected onDisconnect(): void {
this.emit("disconnect");
}
private subscribeToLoginModalEvents(): void {
this.loginModal.on(
LOGIN_MODAL_EVENTS.LOGIN,
async (params: {
adapter: WALLET_ADAPTER_TYPE;
loginParams: unknown;
}) => {
try {
console.log("Wallet Adapters: ", +params.adapter);
await this.web3AuthInstance.connectTo<unknown>(
params.adapter,
params.loginParams
);
} catch (error) {
console.log(
`Error while connecting to adapter: ${params.adapter}`,
error
);
}
}
);
this.loginModal.on(
LOGIN_MODAL_EVENTS.INIT_EXTERNAL_WALLETS,
async (params: { externalWalletsInitialized: boolean }) => {
await this.initExternalWalletAdapters(
params.externalWalletsInitialized
);
}
);
this.loginModal.on(LOGIN_MODAL_EVENTS.DISCONNECT, async () => {
try {
await this.disconnect();
} catch (error) {
console.log(`Error while disconnecting`, error);
}
});
}
private async initExternalWalletAdapters(
externalWalletsInitialized: boolean,
options?: { showExternalWalletsOnly: boolean }
): Promise<void> {
if (externalWalletsInitialized) return;
const adaptersConfig: Record<string, BaseAdapterConfig> = {};
const adaptersData: Record<string, unknown> = {};
const adapterPromises = Object.keys(this.adapters).map(
async (adapterName) => {
try {
const adapter = this.adapters[adapterName];
if (adapter?.type === ADAPTER_CATEGORY.EXTERNAL) {
console.log("init external wallet", adapterName);
this.subscribeToAdapterEvents(adapter);
// we are not initializing cached adapter here as it is already being initialized in initModal before.
if (this.web3AuthInstance.cachedAdapter === adapterName) {
return;
}
if (adapter.status === ADAPTER_STATUS.NOT_READY) {
console.log("Adapter not Ready: " + adapterName);
return await Promise.race([
adapter
.init({
autoConnect:
this.web3AuthInstance.cachedAdapter === adapterName,
})
.then(() => {
adaptersConfig[adapterName] = (
defaultEvmDappModalConfig.adapters as Record<
WALLET_ADAPTER_TYPE,
ModalConfig
>
)[adapterName];
adaptersData[adapterName] = adapter.adapterData || {};
console.log("Adapter Init: ", adapterName);
return adapterName;
}),
new Promise((resolve) => {
setTimeout(() => {
return resolve(null);
}, 5000);
}),
]);
} else {
console.log("Adapter Ready: " + adapterName);
return adapterName;
}
}
} catch (error) {
console.log(error, "error while initializing adapter");
}
}
);
const adapterInitResults = await Promise.all(adapterPromises);
console.log("Adapter Init Results: ", adapterInitResults);
const finalAdaptersConfig: Record<WALLET_ADAPTER_TYPE, BaseAdapterConfig> =
{};
adapterInitResults.forEach((result: string | undefined) => {
if (result) {
finalAdaptersConfig[result] = adaptersConfig[result];
}
});
this.loginModal.addWalletLogins(finalAdaptersConfig, {
showExternalWalletsOnly: !!options?.showExternalWalletsOnly,
});
}
private subscribeToAdapterEvents(walletAdapter: IAdapter<unknown>): void {
console.log("Running adapter events");
walletAdapter.on(ADAPTER_EVENTS.CONNECTED, (data: CONNECTED_EVENT_DATA) => {
let status = ADAPTER_STATUS.CONNECTED;
this.web3AuthInstance.connectedAdapterName = data.adapter;
this.cacheWallet(data.adapter);
console.log(
"connected",
status,
this.web3AuthInstance.connectedAdapterName
);
this.web3AuthInstance.emit(ADAPTER_EVENTS.CONNECTED, {
...data,
} as CONNECTED_EVENT_DATA);
});
walletAdapter.on(ADAPTER_EVENTS.DISCONNECTED, async (data) => {
// get back to ready state for rehydrating.
let status = ADAPTER_STATUS.READY;
if (storageAvailable(this.storage)) {
const cachedAdapter = window[this.storage].getItem(ADAPTER_CACHE_KEY);
if (this.web3AuthInstance.connectedAdapterName === cachedAdapter) {
this.web3AuthInstance.clearCache();
}
}
console.log(
"disconnected",
status,
this.web3AuthInstance.connectedAdapterName
);
this.web3AuthInstance.connectedAdapterName = null;
this.web3AuthInstance.emit(ADAPTER_EVENTS.DISCONNECTED, data);
});
walletAdapter.on(ADAPTER_EVENTS.CONNECTING, (data) => {
let status = ADAPTER_STATUS.CONNECTING;
this.web3AuthInstance.emit(ADAPTER_EVENTS.CONNECTING, data);
console.log(
"connecting",
status,
this.web3AuthInstance.connectedAdapterName
);
});
walletAdapter.on(ADAPTER_EVENTS.ERRORED, (data) => {
let status = ADAPTER_STATUS.ERRORED;
this.web3AuthInstance.clearCache();
this.web3AuthInstance.emit(ADAPTER_EVENTS.ERRORED, data);
console.log(
"errored",
status,
this.web3AuthInstance.connectedAdapterName
);
});
walletAdapter.on(ADAPTER_EVENTS.ADAPTER_DATA_UPDATED, (data) => {
console.log("adapter data updated", data);
this.web3AuthInstance.emit(ADAPTER_EVENTS.ADAPTER_DATA_UPDATED, data);
});
}
private cacheWallet(walletName: string) {
if (!storageAvailable(this.storage)) return;
window[this.storage].setItem(ADAPTER_CACHE_KEY, walletName);
this.web3AuthInstance.cachedAdapter = walletName;
}
}
I got the code from https://forum.moralis.io/t/solved-web3auth-wagmi-connector-doesnt-show-web3-wallets-as-a-login-option/20110/4.
Let me know if it's working for you ?
( You should add all the missing packages with yarn add )
On webrtc debugger I have this from pc1 (call start):
From pc2 (join call):
Have error:
url: stun:54.166.135.129%C2%A0:443
address: 192.168.1.x
port: 59351
host_candidate: 192.168.1.x:59351
error_text: STUN host lookup received error.
error_code: 701
This is code for START CALL:
const startCall = async () => {
sendUser();
localStream = await navigator.mediaDevices.getUserMedia({
video: {
frameRate: 7,
width: 320,
height: 240,
aspectRatio: 1.33333,
},
audio: true,
});
localVideoRef!.current!.srcObject = localStream;
let configuration = {
iceServers: [
{ urls: 'stun:54.166.135.129:443' },
{ urls: 'turn:54.166.135.129 :443', credential: 'user', username: '123' },
],
};
peerConn = new RTCPeerConnection(configuration);
remoteStream = new MediaStream();
// Push tracks from local stream to peer connection
localStream.getTracks().forEach(function (track) {
peerConn.addTrack(track, localStream);
});
// Pull tracks from remote stream, add to video stream
peerConn.ontrack = (event) => {
event.streams[0].getTracks().forEach((track, index) => {
console.log(`REMOTE TRACK ${index + 1}: `, track);
remoteStream.addTrack(track);
});
console.log(remoteStream);
};
peerConn.onicecandidateerror = function (error) {
console.error('On ICE Candidate Error:', error);
};
peerConn.onsignalingstatechange = function (event) {
console.log('Signaling state change:', peerConn.signalingState);
};
peerConn.oniceconnectionstatechange = function (event) {
console.log('ICE connection state change:', peerConn.iceConnectionState);
if (peerConn.iceConnectionState === 'failed') {
console.error('ICE connection failed');
}
};
remoteVideoRef!.current!.srcObject = remoteStream;
peerConn.onicecandidate = (e) => {
if (e.candidate == null) return;
sendData({
type: 'store_candidate',
candidate: e.candidate,
});
};
await createAndSendOffer();
};
const createAndSendOffer = async () => {
const offer = await peerConn.createOffer();
await peerConn.setLocalDescription(offer);
sendData({
type: 'store_offer',
offer: offer,
});}
function sendData(data: { type?: string; candidate?: RTCIceCandidate; offer?: any; id?: string }) {
data.id = id;
console.log('SEND DATA: ', data);
webSocket.send(JSON.stringify(data));
}
function handleSignallingData(data: {
type: any;
answer: RTCSessionDescriptionInit;
offer: RTCSessionDescriptionInit;
candidate: RTCIceCandidateInit | RTCIceCandidate;
}) {
switch (data.type) {
case 'answer':
console.log('ANSWER:', data.answer);
peerConn.setRemoteDescription(new RTCSessionDescription(data.answer));
break;
case 'offer':
console.log('OFFER:', data.offer);
peerConn.setRemoteDescription(data.offer);
createAndSendAnswer();
break;
case 'candidate':
peerConn.addIceCandidate(new RTCIceCandidate(data.candidate));
console.log('CANDIDATE:', data.candidate);
}
}
This is code for JOIN CALL:
webSocket.onmessage = (event) => {
handleSignallingData(JSON.parse(event.data));
};
function handleSignallingData(data: {
type: any;
answer: RTCSessionDescriptionInit;
offer: RTCSessionDescriptionInit;
candidate: RTCIceCandidateInit | RTCIceCandidate;
}) {
switch (data.type) {
case 'answer':
console.log('ANSWER:', data.answer);
peerConn.setRemoteDescription(new RTCSessionDescription(data.answer));
break;
case 'offer':
console.log('OFFER:', data.offer);
peerConn.setRemoteDescription(new RTCSessionDescription(data.offer));
createAndSendAnswer();
break;
case 'candidate':
peerConn.addIceCandidate(new RTCIceCandidate(data.candidate));
console.log('CANDIDATE:', data.candidate);
}
}
function sendData(data: { type?: string; candidate?: RTCIceCandidate; answer?: any; id?: any }) {
data.id = chatUserId;
console.log('SEND DATA: ', data);
webSocket.send(JSON.stringify(data));
}
const joinCall = async (stop?: boolean) => {
localStream = await navigator.mediaDevices.getUserMedia({
video: {
frameRate: 10,
width: 320,
height: 240,
aspectRatio: 1.33333,
},
audio: true,
});
// Let's check if we have current. I have few times exception here
if (!localVideoRef!.current) return;
localVideoRef!.current!.srcObject = localStream;
let configuration = {
iceServers: [
{ urls: 'stun:54.166.135.129:443' },
{ urls: 'turn:54.166.135.129 :443', credential: 'user', username: '123' },
],
};
peerConn = new RTCPeerConnection(configuration);
remoteStream = new MediaStream();
// Push tracks from local stream to peer connection
peerConn.ontrack = (event) => {
event.streams[0].getTracks().forEach((track, index) => {
console.log(`REMOTE TRACK ${index + 1}: `, track);
remoteStream.addTrack(track);
});
console.log(remoteStream);
};
peerConn.onicecandidateerror = function (error) {
console.error('On ICE Candidate Error:', error);
};
peerConn.onsignalingstatechange = function (event) {
console.log('Signaling state change:', peerConn.signalingState);
};
peerConn.oniceconnectionstatechange = function (event) {
console.log('ICE connection state change:', peerConn.iceConnectionState);
if (peerConn.iceConnectionState === 'failed') {
console.error('ICE connection failed');
}
};
remoteVideoRef!.current!.srcObject = remoteStream;
peerConn.onicecandidate = (e) => {
if (e.candidate == null) return;
sendData({
type: 'send_candidate',
candidate: e.candidate,
});
};
sendData({
type: 'join_call',
});
};
const createAndSendAnswer = async () => {
const answer = await peerConn.createAnswer();
await peerConn.setLocalDescription(answer);
sendData({
type: 'send_answer',
// #ts-ignore
answer,
});
};
We have a stun and turn server and we don't understand the problem.
I am testing if a function works,
The function doesn't return anything but infact changes the data in the component
This is the test I am trying to write
describe('ModalAddCollectionCSV', () => {
it('Test load csv function', () => {
const localVue = createLocalVue()
const wrapper = shallowMount(AddCSV, {
localVue,
propsData: {
visible: true,
},
})
var fileDict = [{ file: new Blob([wrongDateFormat]) }]
wrapper.vm.loadcsv(fileDict)
expect(wrapper.html()).toContain('error')
})
})
I am expecting some changes to the data of the component
data() {
return {
collections: [],
inlineVisibility: false,
inlineTitle: '',
inlineSubtitle: '',
inlineKind: 'info',
loading: false,
}
},
This is the function I am testing in unit test, as you see it doesn't return anything just changes the data at the end of it
async loadcsv(element) {
const reader = new FileReader()
const file = element[0].file
this.toggleLoading()
reader.onload = async (e) => {
try {
//Normalising headers
const results = e.target.result
let resultSplit = results.split('\n')
const header = resultSplit[0]
.toLowerCase()
.replace(/[^a-zA-Z,]/g, '')
.trim()
resultSplit[0] = header
let table = resultSplit.join('\n')
const rows = await d3.csvParse(table)
await Promise.all(
rows.map(async (row) => {
if (!(this.getSerial(row).length == 9)) {
if (!this.getName(row)) {
throw `Please enter Person of interest`
}
if (!row.country) {
throw `Country for ${this.getName(
row,
)} is empty`
}
}
)
this.inlineVisibility = false
this.$emit('rowEmit', {
collections: this.row,
})
this.toggleLoading()
this.collections = []
this.$refs.modal.hide()
} catch (err) {
this.collections = []
this.inlineNotification('error', 'Unable to process CSV', `${err}.`)
}
}
reader.readAsText(file)
},
Is there a way to check emit action or error action?
I tried wrapper.text()
Wrapper.html()
but no difference
I'm getting this error
I'm inserting the data into the Clickhouse and i get this error because some of fields are null.
Unknown error field: Code: 117. DB::Exception: Unknown field found while parsing JSONEachRow format: SharesStats: (at row 1): While executing JSONEachRowRowInputFormat. (INCORRECT_DATA) (version 21.11.6.7 (official build))
const Clickhouse = require('#apla/clickhouse');
const { default: axios } = require('axios');
const stockCode = require('./stockCode');
const clickhouse = new Clickhouse({
host: 'localhost',
port: 8123,
username: 'default',
password: '',
dataObjects: true,
queryOptions: {
database: 'stocks'
}
});
const indexStream = clickhouse.query(
'INSERT INTO test2',
{
format: 'JSONEachRow'
},
(err) => {
if (err) {
return console.error(err);
}
}
);
const fetchDataFundamentals = async (stock) => {
try {
const { data: response } = await axios.get(
`https://eodhistoricaldata.com/api/fundamentals/${stock}?api_token=${apiKey}&fmt=json`
);
const nestedFields = [
'SharesStats',
'Technicals',
'SplitsDividends',
'outstandingShares',
'Earnings',
'Financials'
];
const data = {
...response.General,
...response.Highlights,
...response.Valuation,
...response.Holders,
...response.InsiderTransactions,
SharesStats: response.SharesStats,
Technicals: response.Technicals,
SplitsDividends: response.SplitsDividends,
outstandingShares: response.outstandingShares,
Earnings: response.Earnings,
Financials: response.Financials
};
Object.keys(data).forEach((key) => {
if (nestedFields.includes(key)) {
data[key] = Object.keys(data[key]).map((nestedKey) => {
if (!data[key][nestedKey]) {
data[key][nestedKey] = 0;
} else if (typeof data[key][nestedKey] === 'object') {
data[key][nestedKey] = JSON.stringify(data[key][nestedKey]);
}
return data[key][nestedKey];
});
} else if (!data[key]) {
delete data[key];
} else if (typeof data[key] === 'object') {
data[key] = JSON.stringify(data[key]);
}
});
console.log(data);
indexStream.write(data);
indexStream.end();
} catch (error) {
console.error(error.message);
}
};
// Promise.all(stockCode.map((code) => fetchDataFundamentals(code)))
// .then(() => {
// indexStream.end();
// console.log('Fundametals data inserted');
// })
// .catch((err) => {
// console.log(err.message);
// });
try {
fetchDataFundamentals('1010.SR');
} catch (error) {
console.error(error.message);
}
I would like to have more than one Validator instance on my service to handle different languages. Is there any way to implement that?
Something like that:
{
en: new Validator({ messages: { ... }}),
de: new Validator({ messages: { ... }})
// ...
}
It is not available. You should create a custom multi-validators. Here is a quick example:
"use strict";
const _ = require("lodash");
const { ServiceBroker } = require("moleculer");
const BaseValidator = require("moleculer").Validators.Base;
const Validator = require("fastest-validator");
const DefaultMessages = require("fastest-validator/lib/messages");
const { ValidationError } = require("moleculer").Errors;
// --- I18N VALIDATOR CLASS ---
class I18NValidator extends BaseValidator {
constructor(messages) {
super();
0;
this.validators = {};
Object.keys(messages).forEach(lang => {
this.validators[lang] = new Validator();
this.validators[lang].messages = Object.assign({}, DefaultMessages, messages[lang]);
});
}
compile(schema) {
this.checks = {};
Object.keys(this.validators).forEach(lang => {
this.checks[lang] = this.validators[lang].compile(schema);
});
return this.checks;
}
middleware() {
return function I18NValidator(handler, action) {
// Wrap a param validator
if (action.params && typeof action.params === "object") {
const checks = this.compile(action.params);
return function validateContextParams(ctx) {
const check = checks[ctx.meta.lang] || checks["en"];
const res = check(ctx.params);
if (res === true)
return handler(ctx);
else
return Promise.reject(new ValidationError("Parameters validation error!", null, res));
};
}
return handler;
}.bind(this);
}
}
let broker = new ServiceBroker({
logger: true,
validation: true,
validator: new I18NValidator({
"en": {
"string": "The '{field}' field must be a string!"
},
"hu": {
"string": "A '{field}' mezőnek szövegnek kell lennie!"
}
})
});
// --- TEST BROKER ---
broker.createService({
name: "greeter",
actions: {
hello: {
params: {
name: { type: "string", min: 4 }
},
handler(ctx) {
return `Hello ${ctx.params.name}`;
}
}
}
});
broker.start()
// No meta lang
.then(() => broker.call("greeter.hello", { name: 100 }).then(res => broker.logger.info(res)))
.catch(err => broker.logger.error(err.message, err.data))
// "hu" lang
.then(() => broker.call("greeter.hello", { name: 100 }, { meta: { lang: "hu" }}).then(res => broker.logger.info(res)))
.catch(err => broker.logger.error(err.message, err.data))
// "en" lang
.then(() => broker.call("greeter.hello", { name: 100 }, { meta: { lang: "en" }}).then(res => broker.logger.info(res)))
.catch(err => broker.logger.error(err.message, err.data));
It reads the lang from the ctx.meta.lang but you can change it for your case.