Related
I'm trying to develop a chrome extension that access the conversation of WhatsApp Web. I'm struggling to access the Conversation component state (component that I can see with the React developper tools)
When I try
document.querySelector("#main")['__reactFiber$lwbvlqgcvdi']
I get something like this
alternate: zu {tag: 5, key: null, elementType: 'div', type: 'div', stateNode: div#main._1fqrG, …}
child: zu {tag: 0, key: '33619488273-1490436851#g.us', stateNode: null, elementType: ƒ, type: ƒ, …}
childLanes: 1
dependencies: null
elementType: "div"
firstEffect: zu {tag: 5, key: null, elementType: 'div', type: 'div', stateNode: div._26lC3, …}
flags: 0
index: 0
key: null
lanes: 0
lastEffect: zu {tag: 1, key: null, stateNode: t, elementType: ƒ, type: ƒ, …}
memoizedProps: {id: 'main', className: '_1fqrG', style: {…}, children: {…}}
memoizedState: null
mode: 0
nextEffect: null
pendingProps: {id: 'main', className: '_1fqrG', style: {…}, children: {…}}
ref: e=> {…}
return: zu {tag: 10, key: null, elementType: {…}, type: {…}, stateNode: null, …}
sibling: zu {tag: 5, key: null, elementType: 'div', type: 'div', stateNode: div, …}
stateNode: div#main._1fqrG
tag: 5
type: "div"
updateQueue: null
[[Prototype]]: Object
instead of the following result I get when using the React developer tools $r variable
context: {}
props: {setInterval: ƒ, clearInterval: ƒ, setTimeout: ƒ, clearTimeout: ƒ, requestAnimationFrame: ƒ, …}
refs: {}
state: {chat: g, msgCollection: u, focusCtx: {…}, showConversationPreview: false, animate: false, …}
updater: {isMounted: ƒ, enqueueSetState: ƒ, enqueueReplaceState: ƒ, enqueueForceUpdate: ƒ}
_handleCloseChat: e=> {…}
_handleOpenChat: (e,t,a)=> {…}
_handleOpenChatId: 1
_msgCollectionChanged: (e,t,a,s)=> {…}
_newChatScrollInfo: (e,t)=> {…}
_openedChatInfo: {chat: g, renderedMsgsInfo: {…}, visibleMsgOrder: Array(11), clientHeight: 572}
_reactInternals: zu {tag: 1, key: null, stateNode: y, elementType: ƒ, type: ƒ, …}
_refContainer: {current: t.default}
_windowGainedFocus: ()=> {…}
_windowLostFocus: ()=> {…}
[[Prototype]]: m
document.querySelector("#main")['__reactFiber$lwbvlqgcvdi'].stateNodereturns the same element than document.querySelector("#main")['__reactFiber$lwbvlqgcvdi']
document.querySelector("#main")['__reactFiber$lwbvlqgcvdi'].return gives me the context provider wrapping the component
return.stateNode returns null
What do I miss?
I finally figured it out.
It was the great great great great grandparent of the #main element. (Element react developer tools gives me as the matching DOM element for the Conversation component)
Now I know that React developer tools can give the same matching DOM element for different components ^^'
Update
To access the state I was looking for I used the following code :
document.querySelector("#main")['__reactFiber$lwbvlqgcvdi'].return.return.return.return.return.return.stateNode.state
I really found this out of luck as I was crawling up the graph of object out of boredom / despaire / curiosity ^^'
Currently I have many logs by i18next that make difficult to use the console:
I need i18next to use warning level instead of default info level, in order to be able to filter them.
Im checking docs but I dont see any option. My current configuration is:
i18n
.use(XHR)
.use(LanguageDetector)
.init({
debug: true,
lng: 'en',
keySeparator: false,
addMissing: true,
interpolation: {
escapeValue: false
},
resources: {
en: {
translations: translationEng
},
ns: ['translations'],
defaultNS: 'translations'
})
You can disable debug: false, which will disable the default console.log stuff.
And and an event listener missingKey on the i18n instance.
i18n
.use(XHR)
.use(LanguageDetector)
.init({
debug: false, // <-- disable default console.log
lng: 'en',
keySeparator: false,
addMissing: true,
interpolation: {
escapeValue: false
},
resources: {
en: {
translations: translationEng
},
ns: ['translations'],
defaultNS: 'translations'
});
i18n.on('missingKey', (lng, namespace, key, fallbackValue) => {
console.warn(lng, namespace, key, fallbackValue);
})
Based on this code
Other option is to use the options.missingKeyHandler to pass a custom handler for handing missing keys.
i18n
.use(XHR)
.use(LanguageDetector)
.init({
debug: false, // disable this
lng: 'en',
keySeparator: false,
addMissing: true,
interpolation: {
escapeValue: false
},
resources: {
en: {
translations: translationEng
},
ns: ['translations'],
defaultNS: 'translations',
saveMissing: true, // must be enabled
missingKeyHandler: (lng, ns, key, fallbackValue) => {
console.warn(lng, ns, key, fallbackValue)
}
})
Based on this code
I have a login form and where the inputs (email & password) are bound. On clicking the button to submit the form, it prevents the default behaviour and uses the login method defined in the Login.vue; Scripts.
While consoling in Login.vue; Scripts; login method, the form data printed out the {email: 'email', password: 'password'} object (desired). Once it is passed to the action (await this.signIn(this.form)), it consoled out a Vue component all of the sudden. I don't understand why this happened and how can this be solved?
Login.vue Component
Form
<form #submit.prevent="login" method="POST">
<input
type="text"
v-model="form.email"
/>
<input
type="password"
v-model="form.password"
/>
<button class="btn btn-primary">Login</button>
</form>
Scripts
<script>
import { mapActions } from 'vuex'
export default {
data() {
return {
form: {
email: '',
password: '',
},
}
},
computed: {
...mapActions('auth', ['signIn']),
},
methods: {
async login() {
/***************************************
* *
* Print out the form data object *
* *
****************************************/
console.log(this.form)
await this.signIn(this.form)
},
},
}
</script>
Vuex - Auth Module
export const actions = {
signIn({ dispatch, commit }, form) {
/***************************************************************
* *
* Print out a Vue component instead of the passed object *
* *
****************************************************************/
console.log(form)
Auth.signInWithEmailAndPassword(form.email, form.password)
.then(user => {
commit('SET_AUTHENTICATED', true)
commit('SET_USER', user.user)
this.$router.push('/')
})
.catch(err => {
console.log(err)
})
},
}
Console logged content
VueComponent {_uid: 4, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
$attrs: (...)
$children: []
$createElement: ƒ (a, b, c, d)
$el: div
$listeners: (...)
$options: {parent: VueComponent, _parentVnode: VNode, propsData: undefined, _parentListeners: undefined, _renderChildren: undefined, …}
$parent: VueComponent {_uid: 3, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
$refs: {}
$root: Vue {_uid: 2, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
$scopedSlots: {$stable: true, $key: undefined, $hasNormal: false}
$slots: {}
$store: Store {_committing: false, _actions: {…}, _actionSubscribers: Array(1), _mutations: {…}, _wrappedGetters: {…}, …}
$vnode: VNode {tag: "vue-component-4", data: {…}, children: undefined, text: undefined, elm: div, …}
form: (...)
login: ƒ ()
signIn: (...)
__VUE_DEVTOOLS_UID__: "1:4"
_c: ƒ (a, b, c, d)
_computedWatchers: {signIn: Watcher}
_data: {__ob__: Observer}
_directInactive: false
_events: {hook:beforeDestroy: Array(1)}
_hasHookEvent: true
_inactive: null
_isBeingDestroyed: false
_isDestroyed: false
_isMounted: true
_isVue: true
_renderProxy: Proxy {_uid: 4, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
_routerRoot: Vue {_uid: 2, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
_self: VueComponent {_uid: 4, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
_staticTrees: null
_uid: 4
_vnode: VNode {tag: "div", data: undefined, children: Array(2), text: undefined, elm: div, …}
_watcher: Watcher {vm: VueComponent, deep: false, user: false, lazy: false, sync: false, …}
_watchers: (2) [Watcher, Watcher]
$data: (...)
$isServer: (...)
$props: (...)
$route: (...)
$router: (...)
$ssrContext: (...)
get $attrs: ƒ reactiveGetter()
set $attrs: ƒ reactiveSetter(newVal)
get $listeners: ƒ reactiveGetter()
set $listeners: ƒ reactiveSetter(newVal)
get form: ƒ proxyGetter()
set form: ƒ proxySetter(val)
__proto__: Vue
As Sumurai8 mentioned, I only need to put the ...mapActions('auth', ['signIn']) in methods and not in computed.
methods: {
...mapActions('auth', ['signIn']),
async login() {
console.log(this.form)
await this.signIn(this.form)
},
},
I have an object reference from a react component (specifically swiperjs.com react component). I would like to react to changes in the objects properties (https://swiperjs.com/api/#methods), but useEffect() I find does not work in this case, with it being a reference only. Can anyone suggest what to do here?
const [mySwiper, setmySwiper] = useState(0);
useEffect(() => {
console.log(mySwiper.isEnd)
}, [mySwiper]);
Here is the setmySwiper logic, this is a
<Swiper>
...(other parameters)
onSwiper={(swiper) => setmySwiper(swiper)}
</Swiper>
And this is a console.log of mySwiper, it only appears on page refresh despite properties changing during component use:
Swiper {support: {…}, device: {…}, browser: {…}, eventsListeners: {…}, eventsAnyListeners: Array(0), …}
$: ƒ $(selector, context)
$el: Dom7 [div.swiper-container.swiper-container-initialized.swiper-container-vertical, __proto__: (...)]
$wrapperEl: Dom7 [div.swiper-wrapper, __proto__: (...)]
activeIndex: 0
allowClick: true
allowSlideNext: true
allowSlidePrev: true
allowTouchMove: true
animating: false
browser: {isEdge: false, isSafari: false, isWebView: false}
classNames: (2) ["swiper-container-initialized", "swiper-container-vertical"]
device: {ios: false, android: false}
el: div.swiper-container.swiper-container-initialized.swiper-container-vertical
eventsAnyListeners: []
eventsListeners: {_containerClasses: Array(1), _swiper: Array(1), init: Array(2), destroy: Array(2), resize: Array(1), …}
height: 535
imagesLoaded: 4
imagesToLoad: Dom7(4) [img, img, img, img, __proto__: (...)]
initialized: true
isBeginning: true
isEnd: false
isHorizontal: ƒ isHorizontal()
isVertical: ƒ isVertical()
loopCreate: ƒ ()
loopDestroy: ƒ ()
observer: {observers: Array(0), attach: ƒ, init: ƒ, destroy: ƒ}
onClick: ƒ ()
onTouchEnd: ƒ ()
onTouchMove: ƒ ()
onTouchStart: ƒ ()
originalParams: {init: true, direction: "vertical", touchEventsTarget: "container", initialSlide: 0, speed: 320, …}
params: {init: true, direction: "vertical", touchEventsTarget: "container", initialSlide: 0, speed: 320, …}
passedParams: {_emitClasses: false, on: {…}, init: true, direction: "vertical", touchEventsTarget: "container", …}
previousTranslate: 0
progress: -0
realIndex: 0
resize: {resizeHandler: ƒ, orientationChangeHandler: ƒ}
rtl: false
rtlTranslate: false
size: 535
slides: Dom7(4) [div.swiper-slide.swiper-slide-active, div.swiper-slide.swiper-slide-next, div.swiper-slide, div.swiper-slide, __proto__: (...)]
slidesGrid: (4) [0, 535, 1070, 1605]
slidesSizesGrid: (4) [535, 535, 535, 535]
snapGrid: (4) [0, 535, 1070, 1605]
snapIndex: 0
support: {touch: false, pointerEvents: true, observer: true, passiveListener: true, gestures: false}
touchEvents: {start: "pointerdown", move: "pointermove", end: "pointerup"}
touchEventsData: {isTouched: undefined, isMoved: undefined, allowTouchCallbacks: undefined, touchStartTime: undefined, isScrolling: undefined, …}
touchEventsDesktop: {start: "pointerdown", move: "pointermove", end: "pointerup"}
touchEventsTouch: {start: "touchstart", move: "touchmove", end: "touchend", cancel: "touchcancel"}
touches: {startX: 0, startY: 0, currentX: 0, currentY: 0, diff: 0}
translate: -0
velocity: 0
virtualSize: 2140
width: 1903
wrapperEl: div.swiper-wrapper
wrongRTL: false
__proto__: Object
In class based components this is relatively straightforward - you would use componentDidUpdate to get a copy of the previous state and compare it with the new one manually. Functional components do away with the idea of lifecycle methods which can often get bloated and complicated, and instead ask that you tie specific data points together with a specific useEffect to achieve specific things.
You can target the individual properties of mySwiper in different useEffect instances, and those effects will only trigger when the indiviual properties change. For instance, this will only be triggered with changes to the isEnd property:
useEffect(() => {
console.log(mySwiper.isEnd);
}, [mySwiper.isEnd]);
However, if you really want to analyse the entire object in one go, you can use a ref to store the previous value of the state and compare against that. You'll have to check it exists for the first effect pass because refs always initialise as undefined. The bottom line is that if you want to take this approach, you are going to have to do your own object comparison - React isn't going to take care of it for you:
const [mySwiper, setMySwiper] = useState(0);
const prevSwiper = useRef(mySwiper);
useEffect(() => {
if(prevSwiper.current) {
// compare prevSwiper to mySwiper
};
prevSwiper.current = mySwiper;
}, [mySwiper]);
useRef as this.ref = ... doesn’t notify you when its content changes, if you are using hooks you could change your useRef to a useCallback and that would notify you. If that doesn't work for you try using useLayoutEffect
Im writing a small programm for a University project.
I'd like to test it with the pact framewok. Unfortunately, no Pact.json file is created for me, although there are no errors. My Consumer iss written in Javascript.
Below you can see the source code of my javascript file, the console output and my package.json file:
const {Pact} = require('#pact-foundation/pact');
const axios = require('axios');
const path = require('path');
describe('Pact Consumer', () => {
const provider = new Pact({
consumer: 'consumer',
provider: 'producer',
host:'127.0.0.1',
port: 1234,
log: path.resolve(process.cwd(), 'logs', 'pact.log'),
dir: path.resolve(process.cwd(), 'pacts'),
logLevel: 'INFO',
});
beforeAll(() => provider.setup());
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
describe('consumer', () => {
beforeEach
(() =>
provider.addInteraction({
state: "valid date",
uponReceiving: "a request for JSON data",
withRequest: {
method: "GET",
path: "/test",
headers: { Accept: "application/json" },
},
willRespondWith: {
status: 200,
headers: { "Content-Type": "application/json" },
body:
{
name: 'Scherr',
surname: 'Valerian',
age: 28,
},
},
}),
);
});
describe('test', () => {
it('should return the correct data', () => {
return axios.get('localhost:1234/test').then(response => {
expect(response[0].name).toBe('Scherr');
expect(response[0].surname).toBe('Valerian');
expect(response[0].age).toBe(28);
}).then(()=> provider.verify())
});
});
afterAll(() => {
return provider.finalize();
});
});
Console Output:
Error: getaddrinfo ENOTFOUND 1234
Expected :
Actual :
<Click to see difference>
error properties: Object({ errno: 'ENOTFOUND', code: 'ENOTFOUND', syscall: 'getaddrinfo', hostname: '1234', config: Object({ url: 'localhost:1234/test', method: 'get', headers: Object({ Accept: 'application/json, text/plain, */*', User-Agent: 'axios/0.19.2' }), transformRequest: [ Function ], transformResponse: [ Function ], timeout: 0, adapter: Function, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, validateStatus: Function, data: undefined }), request: Writable({ _writableState: WritableState({ objectMode: false, highWaterMark: 16384, finalCalled: false, needDrain: false, ending: false, ended: false, finished: false, destroyed: false, decodeStrings: true, defaultEncoding: 'utf8', length: 0, writing: false, corked: 0, sync: true, bufferProcessing: false, onwrite: Function, writecb: null, writelen: 0, afterWriteTickInfo: null, bufferedRequest: null, lastBufferedRequest: null, pendingcb: 0, prefinished: false, errorEmitted: false, emitClose: true, autoDestroy: false ...
Error: getaddrinfo ENOTFOUND 1234
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:64:26)
package.json:
{
"name": "webservice",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jasmine"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"#pact-foundation/pact": "^9.11.0",
"#pact-foundation/pact-node": "^10.9.5",
"axios": "^0.19.2",
"jasmine": "^3.5.0"
},
"devDependencies": {
"pact": "^4.3.2"
}
}
I am grateful for any help and thanks in advance
I can't tell without logs here, but one things is for sure: your call to axios.get and provider.verify are promises and are not being correctly, meaning the execution of certain things will be out of order or will not actually execute at all.
Simply prefixing both with return should fix that issue.
See https://github.com/pact-foundation/pact-js#test-fails-when-it-should-pass.
I had a similar issue. Setting the cors property on the provider config to true did the job for me.
I didn't seem to have this problem when using node-fetch as opposed to axios.