Store cirular object in localstorage - javascript

I want to store below object into my localstorage and want to use throughout application. For that I used circular function. But when I recreate object from string then it is not same object. Below is my object.
e.exports {client: I}
client: I
browserDetails: {browser: "chrome", version: 80}
permOnClick: true
ringToneFlag: true
ringToneBackFlag: true
connectToneFlag: true
isLoggedIn: true
reconnectInterval: null
reconnectTryCount: 0
localStorage: Storage
length: 13
AsteriskIntegration:ServerIP: ""
auto_saved_sql: "INSERT INTO document_revisions (id,change_log,document_id,doc_id,doc_type,doc_url,date_entered,created_by,filename,file_ext,file_mime_type,revision,deleted,date_modified) VALUES ('e0a40e04-ceb6-dd54-a05d-5e5cc8f4461b','Document Created','390d0e08-1ba9-dcff-1eb8-5e5cc8b83741','','Sugar','','2020-03-02 08:47:40','1','Test.pdf','pdf','application/pdf','1',0,'2020-03-02 08:47:40')"
plivoBrowserSdkJSON: "{"client":{"browserDetails":{"browser":"chrome","version":80},"permOnClick":true,"ringToneFlag":true,"ringToneBackFlag":true,"connectToneFlag":true,"isLoggedIn":true,"reconnectInterval":null,"reconnectTryCount":0,"localStorage":{"AsteriskIntegration:ServerIP":"","endpointID":"001f922acfecfd9498ea0b2b84703ce8f14d2fa55dc96b857bfbfd1ffe9af40d","AsteriskIntegration:Extension":"","AsteriskIntegration:Context":"","AsteriskIntegration:ToggleStatus":"Minimized","AsteriskIntegration:ShowNotification":"0","favorite_tables":"undefined","debug":"","csio_auth_data":"\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWJtaXNzaW9uSW50ZXJ2YWwiOiI1MDAwIiwic2NvcGUiOlsicmVzdC1hcGktaDEiLCJyZXN0LWFwaSIsInN0b3JlLXNkcCIsImh0dHBzOi8vZXZlbnRzLWV1LXdlc3QtMS5jYWxsc3RhdHMuaW8vdjEvYXBwcyIsImh0dHBzOi8vc3RhdHMtZXUtd2VzdC0xLmNhbGxzdGF0cy5pby92MS9hcHBzIiwiaHR0cHM6Ly9hcHBzZXR0aW5ncy1ldS13ZXN0LTEuY2FsbHN0YXRzLmlvL3YxL2FwcHMiLCJodHRwczovL2Rhc2hib2FyZC1ldS13ZXN0LTEuY2FsbHN0YXRzLmlvL2FwcHMiXSwiY29sbGVjdFNEUCI6dHJ1ZSwiYWRhcHRpdmVJbnRlcnZhbCI6ZmFsc2UsImFkYXB0aXZlU3RhdHNFbmFibGVkIjpmYWxzZSwibXVsdGlTRFAiOmZhbHNlLCJ0YWFzRW5hYmxlZCI6ZmFsc2UsInJhd1VzZXJJRCI6ImRhdmlkNTcxOTg5ODM1ODMyOTU0OTIzMSIsInVzZXJJRCI6ImRhdmlkNTcxOTg5ODM1ODMyOTU0OTIzMSIsImp3dGlkQ2hhaW4iOlsiNDIiXSwiZW5kcG9pbnRUeXBlIjoiY2xpZW50IiwiYXBwSUQiOjM4MDA3NzA4NCwicmVzdEFwaVRyYW5zcG9ydCI6dHJ1ZSwicmVuZXdJbnRlcnZhbCI6MzQwMDAwMCwiZXhwaXJ5IjoiMjAyMC0wMi0xM1QwNzoxMDo1MS4zMDZaIiwib3JpZ2luIjpudWxsLCJpYXQiOjE1ODE1NzQ0NTEsImV4cCI6MTU4MTU3ODA1MSwianRpIjoiZWYxYmIxN2YtYzFkNy00MjJlLTg0MDktNTBmODQ4YjJhMmI4In0.FsF6rn82ss9JcAC9UxqUFeCiTe0xl9WDNNeQHBoFc4s\"","AsteriskIntegration:UserID":"1","AsteriskIntegration:SocketPort":""},"_events":{},"_eventsCount":0,"phone":{"_events":{},"_eventsCount":7,"_cache":{"credentials":{}},"_configuration":{"authorization_user":"david","password":null,"realm":"phone.plivo.com","ha1":"2291bb7891ceefc3ab2221cb1565fba6","display_name":null,"uri":{"_parameters":{},"_headers":{},"_scheme":"sip","_user":"david5719898358329549231","_host":"phone.plivo.com"},"contact_uri":{"_parameters":{"transport":"ws"},"_headers":{},"_scheme":"sip","_user":"r594n4dv","_host":"aeqf7b88emss.invalid","_port":null},"instance_id":"78fdf100-2c4d-4deb-a8ac-0cee371db730","use_preloaded_route":false,"session_timers":false,"session_timers_refresh_method":"UPDATE","no_answer_timeout":60000,"register":true,"register_expires":120,"registrar_server":{"_parameters":{},"_headers":{},"_scheme":"sip","_user":null,"_host":"phone.plivo.com"},"connection_recovery_max_interval":20,"connection_recovery_min_interval":2,"via_host":"aeqf7b88emss.invalid","user_agent":"plivo-browser-sdk 2.1.20","plivosip_id":"out4c","hostport_params":"phone.plivo.com"},"_dynConfiguration":{"register":true},"_dialogs":{},"_applicants":{},"_sessions":{},"_transport":{"status":0,"socket":{"_url":"wss://phone.plivo.com:5063","_sip_uri":"sip:phone.plivo.com:5063;transport=ws","_via_transport":"WSS","_ws":{}},"sockets":[{"weight":0,"status":0}],"recovery_options":{"max_interval":20,"min_interval":2},"recover_attempts":0,"recovery_timer":null,"close_requested":false},"_contact":{"pub_gruu":null,"temp_gruu":null},"_status":1,"_error":null,"_transactions":{"nist":{},"nict":{},"ist":{},"ict":{}},"_data":{},"_closeTimer":null,"_registrator":{"_expires":120,"_call_id":"vsa32oc37nnu7143rk274o","_cseq":2,"_registrationTimer":131,"_registering":false,"_registered":true,"_contact":"<sip:r594n4dv#aeqf7b88emss.invalid;transport=ws>;+sip.ice;reg-id=1;+sip.instance=\"<urn:uuid:78fdf100-2c4d-4deb-a8ac-0cee371db730>\"","_extraHeaders":[],"_extraContactParams":""}},"_currentSession":null,"callSession":null,"callUUID":null,"callDirection":null,"lastCallUUID":null,"_lastCallSession":null,"incomingInvites":{},"incomingCallsInitiationTime":{},"lastIncomingCall":null,"callStats":{},"sipAuthBy":null,"userName":"david5719898358329549231","options":{"codecs":["OPUS","PCMU"],"enableTracking":true,"debug":"DEBUG","permOnClick":true,"enableIPV6":false,"audioConstraints":{},"dscp":true,"appId":"380077084","appSecret":null,"registrationDomainSocket":null,"clientRegion":null,"preDetectOwa":false,"disableRtpTimeOut":false,"allowMultipleIncomingCalls":false},"callstatskey":null,"rtp_enabled":null,"statsioused":false,"audio":{"ringtoneDevices":{},"microphoneDevices":{},"speakerDevices":{}},"owaLastDetect":{"time":0,"isOneWay":true},"owaDetectTime":3600000,"outBoundConnectionStages":[],"_outboundExtraHeaders":{},"_outboundCallNumber":null,"statsSocket":null,"bucketApiUrl":"https://stats.plivo.com/v1/browser/bucketurl/","bucketApiBody":{"username":"david5719898358329549231","password":"lokesh","domain":"phone.plivo.com"},"remoteView":{"width":0,"height":0},"ringToneView":{},"ringBackToneView":{},"connectToneView":{},"audioDevDic":["{\"deviceId\":\"default\",\"kind\":\"audioinput\",\"label\":\"Default\",\"groupId\":\"4ce38a6beefca1618312cc984683f32afdd8a031f04697ce4606940d6456d61b\"}","{\"deviceId\":\"d07a50eedfb049ab16b39ddbb545865947600d3673194a608af977f9ce1cf21f\",\"kind\":\"audioinput\",\"label\":\"Built-in Audio Analog Stereo\",\"groupId\":\"e8c51c00b437c50e95499ec3af71c3ad64bd7f204ee5dc3723471a9e0b8a5291\"}","{\"deviceId\":\"default\",\"kind\":\"audiooutput\",\"label\":\"Default\",\"groupId\":\"default\"}","{\"deviceId\":\"aef20cba2448b4d804e2e968682a01c4b1940595ca9b65de3acc0e16ea987338\",\"kind\":\"audiooutput\",\"label\":\"Built-in Audio Analog Stereo\",\"groupId\":\"e8c51c00b437c50e95499ec3af71c3ad64bd7f204ee5dc3723471a9e0b8a5291\"}"]}}"
endpointID: "001f922acfecfd9498ea0b2b84703ce8f14d2fa55dc96b857bfbfd1ffe9af40d"
AsteriskIntegration:Extension: ""
AsteriskIntegration:Context: ""
AsteriskIntegration:ToggleStatus: "Minimized"
AsteriskIntegration:ShowNotification: "0"
favorite_tables: "undefined"
debug: ""
csio_auth_data: ""eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWJtaXNzaW9uSW50ZXJ2YWwiOiI1MDAwIiwic2NvcGUiOlsicmVzdC1hcGktaDEiLCJyZXN0LWFwaSIsInN0b3JlLXNkcCIsImh0dHBzOi8vZXZlbnRzLWV1LXdlc3QtMS5jYWxsc3RhdHMuaW8vdjEvYXBwcyIsImh0dHBzOi8vc3RhdHMtZXUtd2VzdC0xLmNhbGxzdGF0cy5pby92MS9hcHBzIiwiaHR0cHM6Ly9hcHBzZXR0aW5ncy1ldS13ZXN0LTEuY2FsbHN0YXRzLmlvL3YxL2FwcHMiLCJodHRwczovL2Rhc2hib2FyZC1ldS13ZXN0LTEuY2FsbHN0YXRzLmlvL2FwcHMiXSwiY29sbGVjdFNEUCI6dHJ1ZSwiYWRhcHRpdmVJbnRlcnZhbCI6ZmFsc2UsImFkYXB0aXZlU3RhdHNFbmFibGVkIjpmYWxzZSwibXVsdGlTRFAiOmZhbHNlLCJ0YWFzRW5hYmxlZCI6ZmFsc2UsInJhd1VzZXJJRCI6ImRhdmlkNTcxOTg5ODM1ODMyOTU0OTIzMSIsInVzZXJJRCI6ImRhdmlkNTcxOTg5ODM1ODMyOTU0OTIzMSIsImp3dGlkQ2hhaW4iOlsiNDIiXSwiZW5kcG9pbnRUeXBlIjoiY2xpZW50IiwiYXBwSUQiOjM4MDA3NzA4NCwicmVzdEFwaVRyYW5zcG9ydCI6dHJ1ZSwicmVuZXdJbnRlcnZhbCI6MzQwMDAwMCwiZXhwaXJ5IjoiMjAyMC0wMy0xN1QwNToxNTo0NS45MDZaIiwib3JpZ2luIjpudWxsLCJpYXQiOjE1ODQ0MTg3NDUsImV4cCI6MTU4NDQyMjM0NSwianRpIjoiNWQ2ODg4YjctN2E3MC00ZTFkLWJmYTMtODA4MWJiOGYyNjRhIn0.41caOjpo4BbY7qknU9HV-R7HIKhb_4ZiybW6njYcnqQ""
AsteriskIntegration:UserID: "1"
AsteriskIntegration:SocketPort: ""
__proto__: Storage
_events: {}
_eventsCount: 0
_maxListeners: undefined
phone: e.exports {_events: {…}, _eventsCount: 7, _maxListeners: undefined, _cache: {…}, _configuration: {…}, …}
_currentSession: null
callSession: null
callUUID: null
callDirection: null
lastCallUUID: null
_lastCallSession: null
incomingInvites: Map(0) {}
incomingCallsInitiationTime: Map(0) {}
lastIncomingCall: null
callStats: a {}
sipAuthBy: null
userName: "david5719898358329549231"
options: {codecs: Array(2), enableTracking: true, debug: "DEBUG", permOnClick: true, enableIPV6: false, …}
callstatskey: "73aec46c-4893-41ff-aab9-aa23ef9df7f0"
rtp_enabled: true
statsioused: false
audio: {ringtoneDevices: {…}, microphoneDevices: {…}, speakerDevices: {…}, availableDevices: ƒ, revealAudioDevices: ƒ}
audioConstraints: {}
owaLastDetect: {time: 0, isOneWay: true}
owaDetectTime: 3600000
outBoundConnectionStages: []
_outboundExtraHeaders: {}
_outboundCallNumber: null
statsSocket: s {url: "wss://insights.plivo.com/ws", ws: WebSocket, userName: "david5719898358329549231", callstatskey: "73aec46c-4893-41ff-aab9-aa23ef9df7f0"}
statsCallback: ƒ ()
calcConnStage: ƒ (e)
str: ƒ (e)
bucketApiUrl: URL {href: "https://stats.plivo.com/v1/browser/bucketurl/", origin: "https://stats.plivo.com", protocol: "https:", username: "", password: "", …}
bucketApiBody: {username: "david", password: "abc", domain: "phone.plivo.com"}
remoteView: audio#plivo_webrtc_remoteview
ringToneView: audio#plivo_ringtone
ringBackToneView: audio#plivo_ringbacktone
connectToneView: audio#plivo_connect_tone
audioDevDic: (4) ["{"deviceId":"default","kind":"audioinput","label":…2c403010b9047aa8545d46eda66540c5d9fcd4cec87eb17"}", "{"deviceId":"d07a50eedfb049ab16b39ddbb545865947600…9ef43f5d3efef4e5adabc15779e3ce654fd2ff0ae4c72e7"}", "{"deviceId":"default","kind":"audiooutput","label":"Default","groupId":"default"}", "{"deviceId":"aef20cba2448b4d804e2e968682a01c4b1940…9ef43f5d3efef4e5adabc15779e3ce654fd2ff0ae4c72e7"}"]
plivoSocket: e.exports {_url: "wss://phone.plivo.com:5063", _sip_uri: "sip:phone.plivo.com:5063;transport=ws", _via_transport: "WSS", _ws: WebSocket, onconnect: ƒ, …}
heartbeatTimer: 85
__proto__: o
__proto__: Object
And below is my code to convert object to string.
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
var plivoBrowserSdkJSON = JSON.stringify(plivoBrowserSdk, getCircularReplacer());
I followed below answer.
How can I print a circular structure in a JSON-like format?

// create a class with constructor to reinitialise with the data only
You cant serialise function. Coz it is not enumeration properties
class SomeUtil {
constructor({ statsSocket, remoteView, ringToneView, ...rest }) {
this.statsSocket = statsSocket
this.remoteView = remoteView
this.ringToneView = ringToneView // some customization
Object.entries(rest).forEach(([key, value]) => {
this[key] = value
})
}
statsCallback() {
console.log(1)
}
}
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
// File one
function test1() {
const util = new SomeUtil();
util.remoteView = "audio#plivo_webrtc_remoteview"
const onSave = () => {
localStorage.setItem("SomeUtil", JSON.stringify(util, getCircularReplacer()))
}
}
// File 2
function test3() {
const util = new SomeUtil(localStorage.getItem("SomeUtil"));
console.log(util.remoteView)
}
//

Related

Iterate through array in Cypress with assertions JavaScript

I have an array from API call response that looks like this:
[
{
"IsDatalakeEnabled": true,
"RecoveryHr": {
"IsRecoveryHREnabled": false,
"RecoveryHeartRateInterval": 120,
"RecoveryHeartRateSessionTime": 300
}
}
]
I need to get each key:value pair and make assertion that each one exists in other API call response body that looks like this:
...
"StudioAddress": null,
"StudioProfileLanguage": {
"LanguageName": "English",
"LanguageCode": "en"
},
"IsDiversityChannel": true,
"TotalDiversityRadios": 2,
"IsDatalakeEnabled": false,
"IsNetpulse": false,
"RecoveryHeartRateInterval": 120,
"RecoveryHeartRateSessionTime": 300,
"IsRecoveryHREnabled": false,
"StudioPhysicalLocationId": null,
"StudioLocation": null,
"IsIntroCapacityEnabled": false,
"Status": null,
"IsWeb": false,
"OrangeBook": null,
"IsFeReservationEnabled": true,
"TimeZone": "America/New_York",
"IsModifyMaxHr": false,
"IsRunRowEnabled": false,
"WeightMeasure": "LB",
...
Tried cy.each(), but it treats it like one object:
{
"TotalDiversityRadios": "0",
"IsDatalakeEnabled": true
}
Any suggestions/hints would be greatly appreciated. thank you!
tried to convert response body object into array using _.castArray()
Also, tried Object.entries()
Update 01/14/2023
#adoff This is how my test looks like:
validateStudioSettings() {
cy.intercept('POST', '**/studio-settings').as('post')
cy.contains('APPLY').should('be.enabled').click()
cy.get('.dialog-content').should('be.visible').and('have.text', 'Are you sure you want to apply these settings?')
cy.contains('AGREE').click()
cy.get('.notification').should('be.visible').and('contain', 'Success').and('contain', 'Update studio settings successfully.')
cy.wait('#post').then(post => {
expect(post.response.statusCode).equal(200)
expect(post.response.statusMessage).equal('OK')
expect(post.response.body).equal('Update studio settings successfully.')
let studios = _.castArray(post.request.body.StudioIds)
let settings = _.castArray(post.request.body.Settings)//.map(([key, val]) => key + ': ' + val);
console.log('Studios: ', studios)
console.log('Settings: ', settings)
cy.wrap(studios).each((studioId, index) => {
console.log('StudioId: ', studioId, index)
let idToken = localStorage.getItem("idToken")
cy.request({
method: "GET",
url: `/` + studioId,
headers: {
'authorization-cognito': idToken
}
}).then(response => {
cy.wrap(settings).each((setting) => {
console.log('Setting: ', setting)
cy.wrap(response).its('body').then(body => {
let el = _.castArray(body)
console.log('Body: ', el)
expect(el).to.contain(setting)
})
})
})
})
})
}
With this code I'm getting error in Cypress runner:
Cypress Error
Console
This could be done by checking key/value using Object.entries(obj) to give an array of key/value which would be compared to the expected object's key/value.
But there is nesting in the response.
Perhaps you could flatten the response first?
Here's a sample function that would help
const object = {
IsDatalakeEnabled: true,
RecoveryHr: {
IsRecoveryHREnabled: false,
RecoveryHeartRateInterval: 120,
RecoveryHeartRateSessionTime: 300,
},
};
function keyValues(obj) {
return Object.entries(obj).reduce((acc, [key, value]) => {
if (typeof value === "object") {
const kvs = keyValues(value);
acc = acc.concat(kvs);
} else {
acc.push([key, value]);
}
return acc;
}, []);
}
console.log(keyValues(object))
/*
(4) [Array(2), Array(2), Array(2), Array(2)]
0: (2) ['IsDatalakeEnabled', true]
1: (2) ['IsRecoveryHREnabled', false]
2: (2) ['RecoveryHeartRateInterval', 120]
3: (2) ['RecoveryHeartRateSessionTime', 300]
length: 4
*/
In the test:
const expected = {
...
"IsDatalakeEnabled": false,
"IsNetpulse": false,
"RecoveryHeartRateInterval": 120,
"RecoveryHeartRateSessionTime": 300,
...
}
function keyValues(obj) {
return Object.entries(obj).reduce((acc, [key, value]) => {
if (typeof value === "object") {
const kvs = keyValues(value);
acc = acc.concat(kvs);
} else {
acc.push([key, value]);
}
return acc;
}, []);
}
cy.request(...)
.then(response => response.json())
.then(data => {
const obj = data[0]
const kvs = keyValues(obj)
kvs.forEach([key, value] => {
expect(expected(key)).to.eq(value)
})
})

Getting response headers for a get request in angular

I am trying to do a get request using basic auth and need to fetch the token from the response headers. I've gone through similar questions and am doing what was suggested there however I'm still not able to get the required header. Thanks in advance for your help.
Here is my code:
testLogin(): Observable < any > {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Basic ' + btoa('username:password')
}),
observe: 'response'
as 'body'
};
return this.http.get < any[] > ('/login', httpOptions);
}
...
this.service.testLogin().subscribe(r => {
console.log(r.headers);
});
The following is printed on the console:
HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}
lazyInit: () => {…}
lazyUpdate: null
normalizedNames: Map(0)
[[Entries]]
No properties
size: (...)
__proto__: Map
__proto__:
append: ƒ append(name, value)
applyUpdate: applyUpdate(update) { const key = update.name.toLowerCase(); switch (update.op) { case 'a': case 's': let value = update.value; if (typeof value === 'string') { value = [value]; } if (value.length === 0) { return; } this.maybeSetNormalizedName(update.name, key); const base = (update.op === 'a' ? this.headers.get(key) : undefined) || []; base.push(...value); this.headers.set(key, base); break; case 'd': const toDelete = update.value; if (!toDelete) { this.headers.delete(key); this.normalizedNames.delete(key); } else { let existing = this.headers.get(key); if (!existing) { return; } existing = existing.filter(value => {…}
clone: ƒ clone(update)
constructor: class HttpHeaders
copyFrom: copyFrom(other) { other.init(); Array.from(other.headers.keys()).forEach(key => {…}
delete: ƒ delete(name, value)
forEach: forEach(fn) { this.init(); Array.from(this.normalizedNames.keys()) .forEach(key => {…}
get: ƒ get(name)
getAll: ƒ getAll(name)
has: ƒ has(name)
init: init() { if (!!this.lazyInit) { if (this.lazyInit instanceof HttpHeaders) { this.copyFrom(this.lazyInit); } else { this.lazyInit(); } this.lazyInit = null; if (!!this.lazyUpdate) { this.lazyUpdate.forEach(update => {…}
keys: ƒ keys()
maybeSetNormalizedName: ƒ maybeSetNormalizedName(name, lcName)
set: ƒ set(name, value)
__proto__: Object
Have you exposed the token from server-side? In your console log, there is no token I have seen. If there is a token then you can access it as like r.headers.get('token_name'). If you don't expose it from the server-side please see this problem. I may think the first two solutions can help you.
You have to set observe to response:
const httpOptions = {
headers: new HttpHeaders({
"Content-Type": "application/json",
Authorization: "Basic " + btoa("username:password")
}),
observe: "response"
};
Plus, I don't think you can read all the response headers.
You can check the ones that you can read by using the response.headers.keys() method.
this.service.testLogin().subscribe(response => {
response.headers
.keys()
.forEach(keyName =>
console.log(
`The value of the ${keyName} header is: ${response.headers.get(
keyName
)}`
)
);
});
Here's a working Sample Code on StackBlitz for your ref.

Typescript reducer issue

I have the following:
...
type RepairsState = {
data: Property[] /* Property is an object coming from another file */
}
type RepairsPropertyLoadAction = {
type: typeof REPAIRS_PROPERTY_LOAD
payload: { models: Property[] } /* the payload will return an object that has a models property of an array of objects that match my property type */
}
/* Reducer */
export const initialState: RepairsState = {
data: [
{
id: '',
jobNo: '',
trade: '',
priority: '',
status: '',
raisedDate: new Date(),
appointmentDate: new Date(),
completedDate: new Date(),
description: ''
}
]
}
export default function reducer(state = initialState, action: RepairsPropertyLoadAction): RepairsState {
switch (action.type) {
case REPAIRS_PROPERTY_LOAD:
console.log(action.payload)
return {
...state,
data: action.payload
}
default:
return state
}
}
export const getRepairsProperty = (state: AppState) => state.repairs.data
...
Property class:
export default class Property {
id: string = ''
jobNo: string = ''
trade: string = ''
priority: string = ''
status: string = ''
raisedDate: Date = new Date()
appointmentDate: Date = new Date()
completedDate: Date = new Date()
description: string = ''
}
however I am getting the following error:
Type '{ models: Property[]; }' is missing the following properties from type 'Property[]': length, pop, push, concat, and 28 more. TS2740
The action returns an {models: Property []} object for the data, but the state has data: Property []
return {
...state,
data: action.payload.model
}
You are missing the models property, which is defined as part of RepairsPropertyLoadAction. The reducer should be returning this instead:
return {
...state,
data: action.payload.models,
}

why es6 decorator in mobx can't work well?

mobx#3.1.9 use es6 decorator,#log('some_log'), this -> context is Store but don't have model.
decorator is not worl well.
// mobx#3.1.9
const log = type => (target, name, descriptor) => {
console.log(target);
const method = descriptor.value;
descriptor.value = (...args) => {
console.log(type);
let ret;
ret = method.apply(target, args);
};
};
class Store {
#observable age = 20;
model = observable.map({
name: 'Alex',
});
#action
#log('start_log')
setData() {
const res = { name: 'Bob' }
this.age = 30;
this.model.merge(res)
}
}
error log
{constructor: ƒ, setData: ƒ, __mobxLazyInitializers: Array(1)}
age: (...)
$mobx: e {target: {…}, name: "ObservableObject#4", values: {…}, changeListeners: null, interceptors: null}
constructor: ƒ e()
setData: ƒ ()
__mobxDidRunLazyInitializers: true
__mobxLazyInitializers: [ƒ]
get age: ƒ ()
set age: ƒ (t)
__proto__: Object
}
TypeError: Cannot read property 'merge' of undefined
target only have age, no model. why?
the problem is your logger. The target is Store.prototype not the current instance of Store. And this prototype has no property model.
So Store.prototype.model.merge(res) will fail because there is no Store.prototype.model.
const log = type => (target, name, descriptor) => {
console.log(target);
const method = descriptor.value;
descriptor.value = function(...args) {
console.log(type);
console.log(this === target, this, target);
const ret = method.apply(this, args);
};
};

Jest mocked spy function, not being called in test

The component:
The Input component with the onChange handler:
<Field
component={FormattedTextInput}
className={colMd113}
name={NAMES.VEHICLE_YEAR}
label={constants.VEHICLE_YEAR}
validate={[required, validator.validateYearOfVehicle]}
formatting="9999"
onChange={this.yearOnChange}
/>
The method:
constructor(props) {
super(props);
this.yearOnChange = this.yearOnChange.bind(this)
}
yearOnChange(event) {
if (event.target && event.target.value) {
const value = event.target.value;
this.setState({
year: value
});
}
}
The Test
it('yearOnChange method is called', function() {
const spy = jest.spyOn(wrapper.instance(), 'yearOnChange');
wrapper.update();
// const instance = wrapper.instance();
// console.log('instance', instance);
wrapper.simulate('change', {
target: {
name: 'vehicleYear',
value: '1999'
}
});
expect(spy).toHaveBeenCalled();
});
The Error
Vehicle Picker Component › yearOnChange method is called
expect(jest.fn()).toBeCalled()
Expected mock function to have been called, but it was not called.
50 | console.log(wrapper.instance())
51 |
> 52 | expect(spy).toBeCalled();
| ^
53 | });
This is what we see when I log the wrapper.instance()
VehiclePicker {
props: {},
context: {},
refs: {},
updater:
Updater {
_renderer:
ReactShallowRenderer {
_context: {},
_element: [Object],
_instance: [Circular],
_newState: null,
_rendered: [Object],
_rendering: false,
_forcedUpdate: false,
_updater: [Circular],
_dispatcher: [Object],
_workInProgressHook: null,
_firstWorkInProgressHook: null,
_isReRender: false,
_didScheduleRenderPhaseUpdate: false,
_renderPhaseUpdates: null,
_numberOfReRenders: 0 },
_callbacks: [] },
state:
{ year: '',
make: '',
makeArray: [],
model: '',
modelArray: [],
token: '' },
yearOnChange: [Function: bound yearOnChange],
makeOnChange: [Function: bound makeOnChange],
setState: [Function] }
UPDATE
With the following code, the expect(result).toEqual('1999') test works! But still the expect(spy).toHaveBeenCalled() does not :( How is it that when I instantiate the method yearOnChange and actually change the state in the component, that the spy still isn't detected to have been called?
it('yearOnChange method is called', function() {
const spy = jest.spyOn(VehiclePicker.prototype, 'yearOnChange');
wrapper.instance().forceUpdate();
const event = {
target: {
value: '1999'
}
};
wrapper.instance().yearOnChange(event);
wrapper.simulate('change', event);
const result = wrapper.state('year');
console.log('result', result); // result = 1999
expect(result).toEqual('1999');
expect(spy).toHaveBeenCalled();
});
Found great help from the answer here: Jest spyOn function called
This was the important step I was missing:
const instance = wrapper.instance()
const spy = jest.spyOn(instance, 'yearOnChange')
Updated working test with 2 working expects.
it('yearOnChange method is called', function() {
const instance = wrapper.instance(); // <-- Needed to do this here
const spy = jest.spyOn(instance, 'yearOnChange'); // <-- Then use instance here
wrapper.instance().forceUpdate();
const event = {
target: {
value: '1999'
}
};
wrapper.instance().yearOnChange(event);
wrapper.simulate('change', event);
const result = wrapper.state('year');
console.log('result', result); // result = 1999
expect(result).toEqual('1999');
expect(spy).toHaveBeenCalled();
});
You are spying and calling yearOnChange manually.
Try not calling wrapper.instance().yearOnChange(event);
Call the wrapper.instance().onChange event, or like you did, run the simulate('change') will be enough.
You could also try VehiclePicker.prototype.yearOnChange = jest.fn()
expect(VehiclePicker.prototype.yearOnChange).toBeCalled();

Categories