I'm trying to use returned promise from VueFire method $databaseBind (here is the VueFire doc), but unfortunately and I don't know why I have an error this.$databaseBind(...).then() is not a function.
I know that we can have this error when we try call then on non promise value, but $databaseBind should return a promise.
reproduction in codesandbox https://codesandbox.io/s/strange-borg-y41d0u?file=/src/App.vue
Here is my main.js
import { createApp } from "vue";
import App from "./App.vue";
import { VueFire, VueFireDatabaseOptionsAPI } from "vuefire";
createApp(App)
.use(VueFire, {
modules: [VueFireDatabaseOptionsAPI()],
})
.mount("#app");
package.json
{
"name": "happy-new-year",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.8.3",
"firebase": "^9.15.0",
"vue": "^3.2.13",
"vuefire": "^3.0.0"
},
"devDependencies": {
"#babel/core": "^7.12.16",
"#babel/eslint-parser": "^7.12.16",
"#vue/cli-plugin-babel": "~5.0.0",
"#vue/cli-plugin-eslint": "~5.0.0",
"#vue/cli-service": "~5.0.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3"
},
}
firebase.js
import { initializeApp } from "firebase/app";
import { getDatabase } from "firebase/database";
import "firebase/database";
import "firebase/storage";
import "firebase/auth";
const config = {};
export const fb = initializeApp(config);
export const db = getDatabase(fb);
and usage
<template>
<div>{{ testObject.$value }}</div>
</template>
<script>
import { ref } from "firebase/database";
import { db } from "#/plugins/firebase";
export default {
name: "App",
data() {
return {
testObject: {},
};
},
mounted() {
this.$databaseBind("testObject", ref(db, path)).then();
},
};
</script>
Do somebody have any suggestion? Thanks a lot!
There was an inner bug of VueFire. They have fixed it already.
https://github.com/vuejs/vuefire/issues/1275
Related
I am trying to run a test in next.js using jest that imports firebase, but i keep getting an error:
{import { registerVersion } from '#firebase/app'; SyntaxError: Cannot use import statement outside a module
Importing other modules works, but firebase throughs that error. I have tried other enviroments but none seem to work and either throw this error or another error.
Package.JSON:
{
"name": "chat",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "jest --forceExit --watchAll --coverage"
},
"dependencies": {
"#firebase/testing": "^0.20.11",
"firebase": "^9.9.4",
"kill-port": "^2.0.1",
"next": "12.2.5",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-firebase-hooks": "^5.0.3",
"react-hot-toast": "^2.3.0",
"uuid": "^8.3.2"
},
"devDependencies": {
"#babel/plugin-syntax-jsx": "^7.18.6",
"#babel/preset-react": "^7.18.6",
"#firebase/rules-unit-testing": "^2.0.4",
"#testing-library/jest-dom": "^5.16.5",
"#testing-library/react": "^13.4.0",
"#types/jest": "^29.0.2",
"eslint": "8.23.0",
"eslint-config-next": "12.2.5",
"firebase-admin": "^11.0.1",
"jest": "^29.0.3",
"jest-environment-jsdom": "^29.0.3"
}
}
Jest.config.js:
// jest.config.js
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
/** #type {import('jest').Config} */
const customJestConfig = {
// Add more setup options before each test is run
// setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
//moduleDirectories: ['node_modules', '<rootDir>/'],
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);
test/page.test.js
/**
* #jest-environment jest-environment-jsdom
*/
import React from 'react';
import { render, screen } from '#testing-library/react';
import Thing from '../../pages/thing.jsx';
describe('testing Home page', () => {
test('render h1 element', () => {
expect(render(<Thing />));
});
});
pages/test.jsx
import { firestore } from "../lib/firebase";
export default function Thing({ }) {
return (
<main>
</main>
);
}
lib/firebase (Note: removed config fields)
import { initializeApp } from 'firebase/app';
import { getAuth, GoogleAuthProvider } from 'firebase/auth';
import { getFirestore } from 'firebase/firestore';
import { getStorage } from 'firebase/storage';
const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
};
const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const googleAuthProvider = new GoogleAuthProvider();
export const firestore = getFirestore(app);
export const storage = getStorage(app);
React 16.8 | Typescript 3.5
I want to run useEffect to update an array inside App() every time a QR scanner inside a node module imported to the app updates one of its fields.
Alternatively, I would like to receive the data from 'onScan'.
How do you import and use as a dep elements of node module components? There's a page within a file called 'SendPage.jsx' which runs a useState hook called 'setTo()' to update a value 'to'. I'm looking to intercept that 'to' value and use it inside App().
These are my dependencies in node modules. Specifically, inside the "#burner-wallet/modern-ui" there's
"#burner-wallet/assets": "^1.0.0",
"#burner-wallet/core": "^1.0.0",
"#burner-wallet/exchange": "^1.0.0",
"#burner-wallet/modern-ui": "^1.0.9",
"#types/node": "12.0.4",
"#types/react": "*",
"#types/react-dom": "16.8.4",
"#types/react-router-dom": "^4.3.3",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "^3.2.0",
"typescript": "3.5.1",
"universal-cookie": "^4.0.4"
},
This is the package.json inside the "#burner-wallet/modern-ui" module space:
"name": "#burner-wallet/modern-ui",
"version": "1.0.9",
"license": "MIT",
"main": "dist/ModernUI.js",
"types": "dist/ModernUI.d.ts",
"scripts": {
"build": "tsc",
"start-local": "tsc -w",
"start-basic": "tsc -w"
},
"devDependencies": {
"#babel/plugin-proposal-class-properties": "^7.4.4",
"#babel/plugin-proposal-object-rest-spread": "^7.4.4",
"#babel/preset-typescript": "^7.3.3"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
"repository": {
"type": "git",
"url": "https://github.com/burner-wallet/burner-wallet-2.git",
"directory": "packages/modern-ui"
},
"dependencies": {
"#burner-wallet/types": "^1.0.2",
"#burner-wallet/ui-core": "^1.0.2",
"#types/clipboard": "^2.0.1",
"#types/color": "^3.0.0",
"#types/ethereumjs-util": "^5.2.0",
"#types/qrcode.react": "^0.8.2",
"#types/react": "*",
"#types/react-qr-reader": "^2.1.2",
"#types/react-router-dom": "^4.3.4",
"#types/styled-components": "4.1.8",
"clipboard": "^2.0.4",
"color": "^3.1.2",
"ethereumjs-util": "^6.1.0",
"qrcode.react": "^0.9.3",
"react-qr-reader": "^2.2.1",
"styled-components": "^5.0.1"
}
}
My app.tsx file:
import React, { useContext, useEffect, useState } from 'react';
import styled from 'styled-components';
import ScanContext from './scancontext';
import { setLocally, getLocallyStoredQRs } from './localstorage';
// import { xdai, dai, eth } from '#burner-wallet/assets';
import { xdai} from '#burner-wallet/assets';
import BurnerCore, { HistoryEvent } from '#burner-wallet/core';
import { InjectedSigner, LocalSigner } from '#burner-wallet/core/signers';
import { InfuraGateway, InjectedGateway, XDaiGateway, } from '#burner-wallet/core/gateways';
import Exchange, { Uniswap, XDaiBridge } from '#burner-wallet/exchange';
import ModernUI from '#burner-wallet/modern-ui';
import { HistoryProps } from '#burner-wallet/core/History';
const core = new BurnerCore({
signers: [new InjectedSigner(), new LocalSigner()],
gateways: [
new InjectedGateway(),
new InfuraGateway(process.env.REACT_APP_INFURA_KEY),
new XDaiGateway(),
],
// TODO use Sai
// assets: [xdai, dai, eth],
assets: [xdai],
});
const exchange = new Exchange({
pairs: [new XDaiBridge(), new Uniswap('dai')],
});
const QRCardsSpace = styled.div`
padding-bottom: 100px;
`;
function App() {
const [newQRs, setQR] = useState('');
// const storedCookieQRs: string[] = getLocallyStoredQRs();
const appUI = <ModernUI
title="Vincenz Burner Wallet"
core={core}
plugins={[exchange]}
/>
useEffect(() => {
// This will be where the addresses are assigned when read
console.log("useEffect");
console.log("newQRs" , newQRs);
var latestToAddress = "0x4f0f4m";
const QRData = [latestToAddress];
setQR(latestToAddress);
setLocally(QRData);
}, [appUI]); // Set here the conditional change to the QR data
return (
<div>
{appUI}
<QRCardsSpace>
<ScanContext />
</QRCardsSpace>
</div>
) };
export default App;
I've used this test in the past with a React app without any issues:
import { render, fireEvent, screen, waitFor } from '#testing-library/react'
import { RelatedContent } from '../components/relatedcontent'
import { onValue } from '../components/firebase'
jest.mock('../components/firebase')
test('RelatedContent -> displays related content', async () => {
let fakeData = {
'flex-new-row': 20,
'chronlabs': 25
}
let snapshot = {val: () => fakeData}
onValue.mockImplementation((ref, callback) => {
callback(snapshot)
return jest.fn()
})
render(<RelatedContent numRelated = {5}/>)
await waitFor(() => expect(document.querySelector("a[href='/flex-new-row']")).toBeTruthy())
await waitFor(() => expect(document.querySelector("a[href='/chronlabs']")).toBeTruthy())
})
Now I'm using the same test on a Next.js app, and I'm getting the following error:
TypeError: _firebase.onValue.mockImplementation is not a function
Update
The RelatedContent component looks like:
import React, { useState, useEffect } from 'react'
import { db, onValue, ref } from './firebase'
const RelatedContent = ({ numRelated }) => {
const [related, setRelated] = useState([])
useEffect(() => {
let unsubscribe = onValue(ref(db, `posts/related`), snapshot => {
let _related = Object.keys(snapshot.val())
setRelated(_related)
})
return () => unsubscribe()
}, [])
return(
<div className = 'Related'>
{related.slice(0, numRelated).map((elem, i) =>
<Link href = {elem}>Whatever</Link>
)}
</div>
)
}
export default RelatedContent
And the Firebase component looks like:
import { initializeApp } from 'firebase/app'
import { getDatabase, goOnline, goOffline, limitToLast, onDisconnect, onValue, orderByValue, push, query, ref, remove, runTransaction, update } from 'firebase/database'
const config = { ... }
const app = initializeApp(config)
const db = getDatabase(app)
export { db, dbt, goOnline, goOffline, limitToLast, onDisconnect, onValue, orderByValue, push, query, ref, remove, runTransaction, update }
package.json looks like:
{
"name": "app-next",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "jest"
},
"dependencies": {
"#primer/octicons-react": "^16.3.0",
"chart.js": "^2.7.2",
"firebase": "^9.6.4",
"gfm": "0.0.1",
"moment": "^2.29.1",
"next": "12.0.8",
"prismjs": "^1.26.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-markdown": "^8.0.0",
"rehype-katex": "^6.0.2",
"rehype-raw": "^6.1.1",
"remark-gfm": "^3.0.1",
"remark-math": "^5.1.1"
},
"devDependencies": {
"#testing-library/jest-dom": "^5.16.1",
"#testing-library/react": "^12.1.2",
"eslint": "8.7.0",
"eslint-config-next": "12.0.8",
"eslint-plugin-promise": "^6.0.0",
"jest": "^27.4.7"
}
}
If I place the fake data and the onValue.mockImplementation() function before the test declaration, the test passes correctly.
The problem is that I've several tests with multiple definitions of the fake data, and I need to declare the fake data within every test.
If I do so, I get the error.
I have an issue with vue js , I want to use VueRouter to link 2 vue component, but it seems I have an issue with Vue.use, I have this error :
I don't think the problem is about VueRouter but more about vue import I'm kinda lost at this point
//This is my app.js
import Welcome from "./Jetstream/Welcome";
require('./bootstrap');
window.Vue = require('vue');
console.log(window.vue)
// Import modules...
import { createApp, h } from 'vue';
import Vue from 'vue'
import { App as InertiaApp, plugin as InertiaPlugin } from '#inertiajs/inertia-vue3';
import { InertiaProgress } from '#inertiajs/progress';
import Router from 'vue-router'
Vue.use(Router)
const router = new VueRouter({
mode: 'history',
routes:
{
path: '/student',
name: 'student',
component: Welcome
},
});
const el = document.getElementById('app');
createApp({
render: () =>
h(InertiaApp, {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: (name) => require(`./Pages/${name}`).default,
}),
})
.mixin({ methods: { route } })
.use(InertiaPlugin)
.mount(el);
InertiaProgress.init({ color: '#4B5563' });
<template>
<div>Hello</div>
<!-- this is My vue component-->
<!-- i try use a simple method-->
<a class="btn btn-primary" #click="truc"> Test</a>
<!--And this is what I swa on the documentation-->
<router-link :to="{name: 'student'}">Student</router-link>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "Session.vue",
methods:{
truc(){
this.$router.push('/student')
}
}
}
</script>
If you need more content tell me, thanks for your help
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "npm run production",
"production": "mix --production"
},
"devDependencies": {
"#inertiajs/inertia": "^0.9.1",
"#inertiajs/inertia-vue3": "^0.4.2",
"#inertiajs/progress": "^0.2.5",
"#tailwindcss/forms": "^0.2.1",
"#tailwindcss/typography": "^0.3.0",
"#vue/compiler-sfc": "^3.0.5",
"axios": "^0.21.1",
"laravel-mix": "^6.0.6",
"lodash": "^4.17.19",
"postcss": "^8.1.14",
"postcss-import": "^12.0.1",
"tailwindcss": "^2.2.4",
"vue": "^3.1.5",
"vue-loader": "^16.1.2"
},
"dependencies": {
"bootstrap": "^5.0.2",
"bootstrap-icons": "^1.5.0",
"bootstrap-vue": "^2.21.2",
"vform": "^2.1.0",
"vue-i18n": "^8.24.5"
}
}
this is my package.json
But I have this in my dependencies :
My app.js is now like that :
I think you use Vue 3, not Vue 2. Because of that you should assign createApp(...) to a variable
let app = createApp(...)
Also you need to do:
import {createRouter} from 'vue-router'
and setup:
const router = createRouter(...)
Then you do
app.use(router)
See how it looks like in docs:
https://next.router.vuejs.org/guide/#javascript
Any ideas why I am getting the following this "dispatch is not a function" error in my listEventsActionCreator function when it calls "dispatch(listEventsRequestedAction())" ???
If I comment out the lines in this method after the dispatch it actually then works which is strange.
Using react-create-app, with redux, typescript, thunk.
ERROR:
TypeError: dispatch(...) is not a function
CODE:
export function listEventsRequestedAction() {
return {
type: PlannerEventTypes.LIST_EVENTS_REQUESTED
}
}
export const listEventsReceivedAction = (events:PlannerEvent[]) => {
return {
type: PlannerEventTypes.LIST_EVENTS_RECEIVED,
events
}
}
export const listEventsErrorAction = (err:any) => {
return {
type: PlannerEventTypes.LIST_EVENTS_ERROR,
error: err
}
}
export const listEventsActionCreator = () => {
return (dispatch: any) => {
dispatch(listEventsRequestedAction()) // <== ERROR: TypeError: dispatch(...) is not a function
(API.graphql(graphqlOperation(listEvents)) as Promise<any>).then((results:any) => {
const events = results.data.listEvents.items
dispatch(listEventsReceivedAction(events))
}).catch((err:any) => {
// console.log("ERROR")
dispatch(listEventsErrorAction(err))
})
}
}
package.json
{
"name": "planner",
"version": "0.1.0",
"private": true,
"dependencies": {
"#types/graphql": "^14.0.7",
"#types/react-redux": "^6.0.10",
"aws-amplify": "^1.1.19",
"aws-amplify-react": "^2.3.0",
"date-fns": "^1.30.1",
"eslint": "^5.9.0",
"konva": "^2.5.1",
"moment": "^2.22.2",
"moment-timezone": "^0.5.23",
"react": "^16.6.3",
"react-dom": "^16.6.3",
"react-draggable": "^3.0.5",
"react-konva": "^16.6.31",
"react-moment": "^0.8.4",
"react-redux": "^5.1.1",
"react-scripts-ts": "3.1.0",
"redux": "^4.0.1",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.3.0"
},
"scripts": {
"start": "react-scripts-ts start",
"build": "react-scripts-ts build",
"test": "react-scripts-ts test --env=jsdom",
"eject": "react-scripts-ts eject"
},
"devDependencies": {
"#types/jest": "^23.3.10",
"#types/node": "^10.12.10",
"#types/react": "^16.7.10",
"#types/react-dom": "^16.0.11",
"#types/redux-logger": "^3.0.7",
"typescript": "^3.2.1"
}
}
index.tsx
import * as React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { applyMiddleware, createStore } from 'redux'
import App from './App'
import './index.css'
import rootReducer from './reducers/index'
import registerServiceWorker from './registerServiceWorker'
import { createLogger } from 'redux-logger'
import thunkMiddleware from 'redux-thunk'
const loggerMiddleware = createLogger()
const store = createStore (
rootReducer,
applyMiddleware(
thunkMiddleware, // lets us dispatch() functions
loggerMiddleware // neat middleware that logs actions
)
)
render(
<Provider store={store}>
<App testStr='test' />
</Provider>
,document.getElementById('root') as HTMLElement
);
registerServiceWorker();
The problem is because of the syntax that you followed. You don't have a semicolon after dispatch(listEventsRequestedAction()) and since you follow it up with (API.graphql(graphqlOperation(listEvents) as Promise<any>) while compiling it is evaluted as dispatch(listEventsRequestedAction())(API.graphql(graphqlOperation(listEvents) as Promise<any>) and hence it gives you the error.
Adding a semicolon after dispatch(listEventsRequestedAction()) would work
export const listEventsActionCreator = () => {
return (dispatch: any) => {
dispatch(listEventsRequestedAction());
(API.graphql(graphqlOperation(listEvents)) as Promise<any>).then((results:any) => {
const events = results.data.listEvents.items
dispatch(listEventsReceivedAction(events))
}).catch((err:any) => {
// console.log("ERROR")
dispatch(listEventsErrorAction(err))
})
}
}
P.S. The semicolon is not required in Javascript and would not cause a
js error on its own. It could however cause an error if concatenating
with other scripts.