A non-serializable value was detected in the state: redux toolkit - node.js

I am trying to implement Redux toolkit store in a react native application. It is my first time. I am using axios to make requests to the API.
I am getting this error on a post request:
A non-serializable value was detected in the state, in the path: `user`. Value: {"_A": null,
"_x": 0, "_y": 0, "_z": null}
Take a look at the reducer(s) handling this action type: userreg/fulfilled.
Here are my codes:
const initialState={
token: '',
session: '',
loading: false,
}
export const logInUser = createAsyncThunk('userreg', async(name, thunkAPI)=>{
const {user_username, user_password} = name
//const m = JSON.stringify(name)
const res = await axios.post(`${BASE_URL}/login`,
{
user_username, user_password
}
)
//console.log(res.data)
return res.data
})
const userSlice = createSlice({
name: 'user',
initialState,
reducers:{
addSession:(state, action)=>{
state.session = AsyncStorage.getItem('sessionId')
},
addToken:(state, action)=>{
state.token = AsyncStorage.getItem('token')
}
},
extraReducers: (builders)=>{
builders.addCase(logInUser.pending, (state, action)=>{
state.loading = true
})
builders.addCase(logInUser.fulfilled, async(state, {payload})=>{
console.log(payload, 'slode ier')
state.loading = false
state.token = payload.userToken;
state.session = payload.session;
await AsyncStorage.setItem('sessionId', payload.session);
await AsyncStorage.setItem('token', payload.userToken)
})
}
})
export default userSlice.reducer;
const handleUserLog = async ()=>{
const logDetails = {
user_username: userLogin.user_username,
user_password: userLogin.user_password,
}
dispatch(logInUser(logDetails))
}
When I implemented the same code with fetch instead of axios to make the same request to the API, it didn't give this error.

Related

Net to setup simple if and else statement in node.js

trying to setup node.js code
i want to setup simple if and else
can anyone help to setup if and else
// To use any npm package on Pipedream, just import it
import axios from "axios"
export default defineComponent({
async run({ steps, $ }) {
const { data } = await axios(
{
method: "POST",
url: `http://xxx.xx.xx.xxx:3000/message/text?key=kjashdkasdhkjashsad`,
if(steps.trigger.event.body.info.to_pincode == '411045' )
{
data: {
id: "919999999999",
message: 'Name steps.zoho_books.$return_value.contacts[0].contact_name\nItem Name steps.trigger.event.body.product_name\nAWB steps.trigger.event.body.courier_tracking_id\nCourier Name steps.trigger.event.body.courier_parent_name\nCurrent Location steps.trigger.event.body.status.current_status_location \nCurrent Status steps.trigger.event.body.status.current_status_body\nDelivery City steps.trigger.event.body.info.to_city\nDelivery State steps.trigger.event.body.info.to_state\nEstimated Delivery Date steps.trigger.event.body.edd_stamp }}
else{
data: {
id: "919999999999",
message: 'Else steps.zoho_books.$return_value.contacts[0].contact_name\nItem Name steps.trigger.event.body.product_name\nAWB steps.trigger.event.body.courier_tracking_id\nCourier Name steps.trigger.event.body.courier_parent_name\nCurrent Location steps.trigger.event.body.status.current_status_location \nCurrent Status steps.trigger.event.body.status.current_status_body\nDelivery City steps.trigger.event.body.info.to_city\nDelivery State steps.trigger.event.body.info.to_state\nEstimated Delivery Date steps.trigger.event.body.edd_stamp }}
})
return data.species
},
})
Try to use a conditional operator to define your data object:
import axios from 'axios';
export default defineComponent({
async run({ steps, $ }) {
const dataObj =
steps.trigger.event.body.info.to_pincode == '411045'
? {
id: '919999999999',
message: 'if',
}
: { id: '919999999999', message: 'else' };
const { data } = await axios({
method: 'POST',
url: `http://xxx.xx.xx.xxx:3000/message/text?key=kjashdkasdhkjashsad`,
data: dataObj,
});
return data.species;
},
});

How to make kuzzle-device-manager plugin API actions works?

I successfully installed and loaded kuzzle-device-manager in the backend file:
import { Backend } from 'kuzzle';
import { DeviceManagerPlugin } from 'kuzzle-device-manager';
const app = new Backend('playground');
console.log(app.config);
const deviceManager = new DeviceManagerPlugin();
const mappings = {
updatedAt: { type: 'date' },
payloadUuid: { type: 'keyword' },
value: { type: 'float' }
}
deviceManager.devices.registerMeasure('humidity', mappings)
app.plugin.use(deviceManager)
app.start()
.then(async () => {
// Interact with Kuzzle API to create a new index if it does not already exist
console.log(' started!');
})
.catch(console.error);
But when i try to use controllers from that plugin for example device-manager/device with create action i get an error output.
Here is my "client" code in js:
const { Kuzzle, WebSocket } = require("kuzzle-sdk")
const kuzzle = new Kuzzle(
new WebSocket('KUZZLE_IP')
)
kuzzle.on('networkError', error => {
console.error('Network Error: ', error);
})
const run = async () => {
try {
// Connects to the Kuzzle server
await kuzzle.connect();
// Creates an index
const result = await kuzzle.query({
index: "nyc-open-data",
controller: "device-manager/device",
action: "create",
body: {
model: "model-1234",
reference: "reference-1234"
}
}, {
queuable: false
})
console.log(result)
} catch (error) {
console.error(error.message);
} finally {
kuzzle.disconnect();
}
};
run();
And the result log:
API action "device-manager/device":"create" not found
Note: The nyc-open-data index exists and is empty.
We apologize for this mistake in the documentation, the device-manager/device:create method is not available because the plugin is using auto-provisioning until the v2.
You should send a payload to your decoder, the plugin will automatically provision the device if it does not exists https://docs.kuzzle.io/official-plugins/device-manager/1/guides/decoders/#receive-payloads

Jest Test suite failed to run - AssertionError [ERR_ASSERTION]: opts.entryPoint required

We had a test running successfully for our code that uses the notifications-node-client to send emails, eg
import { NotifyClient } from 'notifications-node-client';
import notify from './notify';
import config from '../../../config';
jest.mock('fs');
jest.mock('notifications-node-client');
describe('notify', () => {
const EMAIL = 'user#test.com';
const REGION_GB = 'gb';
const REGION_NI = 'ni';
const feedbackOptions = {
personalisation: {
satisfactionLevel: 'satisfied',
improvements: 'improvements',
},
};
test('for original GB submission sendEmail should be called and true returned', async () => {
NotifyClient.prototype.sendEmail.mockReturnValue({
body: {
id: 1,
},
});
expect(await notify(EMAIL, 'submissionSuccess', REGION_GB)).toBeTruthy();
expect(NotifyClient.prototype.sendEmail).toHaveBeenCalledWith(
config.notify.templates.submissionSuccess.gb,
EMAIL,
undefined,
);
});
...
Having swapped out our Winston logging solution to use #dwp/node-logger, the 'notify' tests now do not run, failing with
● Test suite failed to run
AssertionError [ERR_ASSERTION]: opts.entryPoint required
at new Thrift (node_modules/thriftrw/thrift.js:64:5)
at Object.<anonymous> (node_modules/jaeger-client/src/thrift.js:21:20)
at Object.<anonymous> (node_modules/jaeger-client/src/reporters/remote_reporter.js:15:1)
All of the other test suites in the project still run successfully.
Could anyone point me in the right direction about what change to make?
The code that we're testing is
import { NotifyClient } from 'notifications-node-client';
import config from '../../../config/index';
import { RegionKeys } from '../../../config/types';
import logger from '../../../xxxx/lib/logger';
type TemplateId = 'submissionSuccess' | 'supportingEvidence' | 'feedbackTemplateId';
type FeedbackOptions = {
personalisation: {
satisfactionLevel: string,
improvements: string,
},
reference?: string,
}
const { apiKey, templates, proxy } = config.notify;
export default async function notify(
email: string,
templateId: TemplateId,
region: RegionKeys,
options?: FeedbackOptions,
): Promise<boolean> {
let notifyTemplate;
let notifyApiKey;
let notifyOptions;
try {
if (templateId === 'feedbackTemplateId' && !options) {
throw new Error(`Unable to send email - mismatch between template ID (${templateId}) and options supplied`);
} else if (options && templateId !== 'feedbackTemplateId') {
notifyOptions = {};
} else {
notifyOptions = options;
}
const notifyClient = new NotifyClient(apiKey[region]);
notifyClient.setProxy(proxy);
notifyTemplate = templateId === 'feedbackTemplateId' ? templates.feedbackTemplateId : templates[templateId][region];
logger.debug(`apiKey: ${notifyApiKey}`);
logger.debug(`notify template Id: ${notifyTemplate}`);
logger.debug(`proxy: ${JSON.stringify(proxy)}`);
const response = await notifyClient.sendEmail(notifyTemplate, email, notifyOptions);
if (response.body) {
logger.info(`confirmation email sent to ${email} and relates to message id ${response.body.id}`);
}
return true;
} catch (err: any) {
logger.error(`there was an error sending the message: ${err.message}`);
return false;
}
}

Mock multiple api call inside one function using Moxios

I am writing a test case for my service class. I want to mock multiple calls inside one function as I am making two API calls from one function. I tried following but it is not working
it('should get store info', async done => {
const store: any = DealersAPIFixture.generateStoreInfo();
moxios.wait(() => {
const request = moxios.requests.mostRecent();
request.respondWith({
status: 200,
response: store
});
const nextRequest = moxios.requests.at(1);
nextRequest.respondWith({
status: 200,
response: DealersAPIFixture.generateLocation()
});
});
const params = {
dealerId: store.dealerId,
storeId: store.storeId,
uid: 'h0pw1p20'
};
return DealerServices.retrieveStoreInfo(params).then((data: IStore) => {
const expectedOutput = DealersFixture.generateStoreInfo(data);
expect(data).toMatchObject(expectedOutput);
});
});
const nextRequest is always undefined
it throw error TypeError: Cannot read property 'respondWith' of undefined
here is my service class
static async retrieveStoreInfo(
queryParam: IStoreQueryString
): Promise<IStore> {
const res = await request(getDealerStoreParams(queryParam));
try {
const locationResponse = await graphQlRequest({
query: locationQuery,
variables: { storeId: res.data.storeId }
});
res.data['inventoryLocationCode'] =
locationResponse.data?.location?.inventoryLocationCode;
} catch (e) {
res.data['inventoryLocationCode'] = 'N/A';
}
return res.data;
}
Late for the party, but I had to resolve this same problem just today.
My (not ideal) solution is to use moxios.stubRequest for each request except for the last one. This solution is based on the fact that moxios.stubRequest pushes requests to moxios.requests, so, you'll be able to analyze all requests after responding to the last call.
The code will look something like this (considering you have 3 requests to do):
moxios.stubRequest("get-dealer-store-params", {
status: 200,
response: {
name: "Audi",
location: "Berlin",
}
});
moxios.stubRequest("graph-ql-request", {
status: 204,
});
moxios.wait(() => {
const lastRequest = moxios.requests.mostRecent();
lastRequest.respondWith({
status: 200,
response: {
isEverythingWentFine: true,
},
});
// Here you can analyze any request you want
// Assert getDealerStoreParams's request
const dealerStoreParamsRequest = moxios.requests.first();
expect(dealerStoreParamsRequest.config.headers.Accept).toBe("application/x-www-form-urlencoded");
// Assert graphQlRequest
const graphQlRequest = moxios.requests.get("POST", "graph-ql-request");
...
// Assert last request
expect(lastRequest.config.url).toBe("status");
});

Testing and mocking fetch in async useEffect and async Redux-Saga

I'm testing a functional component, that use React-Hooks and Redux-Saga. I can pass parameters in URL for the component, because they are a login page component.
My URL i pass is 'localhost/access/parameter', and when this parameter exists, i need to call a async redux saga, and if the fetch is OK, i put the result in redux-store. When the result is on redux-store, i have a useEffect that verify the result and if is OK, i put her in a input.
I can mock the result with axios, but i'm migrating to use only fetch. i mock the fetch, but when i use
mount(component), provided by enzyme, i do not how to await the redux-saga termine the request and useEffect do your job. I put a console log inside a effect, saga and log the input props to see your value prop, but the value is always empty . I tried to use setImmediate() and process.nextTick().
Links i use to write the code: 1,2, 3
I'm using formik, so they pass some props to me.
My component
const Login = ({
setFieldError, errors, response, fetchDomain, location, values, handleChange, handleBlur, setFieldValue, history,
}) => {
useEffect(() => {
async function fetchUrlDomain() {
const { pathname } = location;
const [, , domain] = pathname.split('/');
if (typeof domain !== 'undefined') {
await fetchDomain(domain);
}
}
fetchUrlDomain();
}, [fetchDomain, location]);
useEffect(() => {
if (typeof response === 'string') {
setFieldError('domain', 'Domain not found');
inputDomain.current.focus();
} else if (Object.keys(response).length > 0) {
setFieldValue('domain', response.Domain);
setFieldError('domain', '');
}
}, [response, setFieldValue, setFieldError]);
return (
<input name="domain" id="domain" value={values.domain} onChange={handleChange} onBlur={handleBlur} type="text" />
);
}
const LoginFormik = withFormik({
mapPropsToValues: () => ({ domain: '' }),
enableReinitialize: false,
validateOnBlur: false,
validateOnChange: false,
})(Login);
const mapStateToProps = () => ({ });
const mapDispatchToProps = dispatch => ({
fetchDomain: (value) => {
dispatch(action({}, constants.RESET_RESPONSE_DOMAIN));
dispatch(action(value, constants.FETCH_DOMAIN_REQUEST));
},
});
export default connect(mapStateToProps, mapDispatchToProps)(LoginFormik);
My Saga
export function* fetchDomain(action) {
const url = yield `${mainUrl}/${action.payload}`;
try {
const response = yield fetch(url).then(res => res.json());
yield put(reduxAction(response , constants.FETCH_DOMAIN_SUCCESS));
} catch (e) {
yield put(reduxAction(e, constants.FETCH_DOMAIN_FAILURE));
}
}
My Reducer
case constants.FETCH_DOMAIN_FAILURE:
return { ...initialState, response: 'Domain not found' };
case constants.FETCH_DOMAIN_SUCCESS: {
const { payload } = action;
return {
...initialState,
id: payload.Id,
apis: payload.Apis,
response: payload,
};
}
case constants.RESET_RESPONSE_DOMAIN:
return { ...initialState };
My Test
it('input with fetch only', (done) => {
const mockSuccessResponse = {
Id: 'fafafafa',
Apis: [],
Domain: 'NAME',
};
const mockJsonPromise = Promise.resolve(mockSuccessResponse);
const mockFetchPromise = Promise.resolve({
json: () => mockJsonPromise,
});
global.fetch = jest.fn().mockImplementation(() => mockFetchPromise);
const wrapper = mount(
<Provider store={store}>
<LoginForm
history={{ push: jest.fn() }}
location={{ pathname: 'localhost/login/Domain' }}
/>
</Provider>,
);
process.nextTick(() => {
const input = wrapper.find('#domain');
console.log(input.props());
expect(input.props().value.toLowerCase()).toBe('name');
global.fetch.mockClear();
done();
});
});
I expect my input have value, but he don't. I tried to use jest-fetch-mock but just don't work, and i want to use native jest methods, no thirty party libraries.
I cannot say what's wrong with your current code. But want to propose different approach instead.
Currently you are testing both redux part and component's one. It contradicts with unit testing strategy when ideally you should mock everything except module under the test.
So I mean if you focus on testing component itself it'd be way easier(less mocks to create) and more readable. For that you need additionally export unwrapped component(Login in your case). Then you can test only its props-vs-render result:
it('calls fetchDomain() with domain part of location', () => {
const fetchDomain = jest.fn();
const location = { pathName: 'example.com/path/sub' }
shallow(<Login fetchDomain={fetchDomain} location={location} />);
expect(fetchDomain).toHaveBeenCalledTimes(1);
expect(fetchDomain).toHaveBeenCalledWith('example.com');
});
it('re-calls fetchDomain() on each change of location prop', () => {
const fetchDomain = jest.fn();
const location = { pathName: 'example.com/path/sub' }
const wrapper = shallow(<Login fetchDomain={fetchDomain} location={location} />);
fetchDomain.mockClear();
wrapper.setProps({ location: { pathName: 'another.org/path' } });
expect(fetchDomain).toHaveBeenCalledTimes(1);
expect(fetchDomain).toHaveBeenCalledWith('another.org');
});
And the same for other cases. See with this approach if you replace redux with direct call to fetch() or whatever, or if you refactor that data to come from parent instead of reading from redux store you will not need to rewrite tests removing mocks to redux. Sure, you will still need to test redux part but it also can be done in isolation.
PS and there is no profit to await fetchDomain(...) in useEffect since you don't use what it returns. await does not work like a pause and that code may rather confuse reader.

Resources