Cypress 10 - variables between cypress tests - cypress

I am trying to get a value from response body and then using it in another it-s in Cypress 10. I have created custom cy.task for get and set global variable, but it's not a good solution when I need for example 10 values from previous test:
await cy.task("getValue", {key: "one"}).then((one){
await cy.task("getValue", {key: "two"}).then((two){
await cy.task("getValue", {key: "three"}).then((three){
await cy.task("getValue", {key: "four"}).then((four){
...
if(one === null && two === null && three == null && four == null){
do smth
}
});
});
});
});
Another solution is get value from cy.task and save it into local variable:
let one_helper;
let two_helper;
let ...
cy.task("getValue", {key: "one"}).then((one){
one_helper = one;
}
cy.task("getValue", {key: "two"}).then((two){
two_helper = two;
}
...
if(one_helper == null && two_helper == null){
do smth
}
But it's not a good solution for me because I have a lots of values from previous response.

You can use Cypress.env() to save any value globally.
Cypress.env('somekey', 'somevalue') //saves the value
Cypress.env('somekey') //gets 'somevalue'

You could pass an array of keys to one task call.
const { defineConfig } = require('cypress')
const store = {}
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('task', {
getValue(keys) {
if (typeof keys === 'string') { // only a single key?
keys = [keys] // arrayify it
}
return keys.map(key => store[key])
},
})
}
}
})

Related

fetch list of data got incomplete result, how to remove the limitation

i try to get all the data which is belong to logged user but got incomplete result, it suppose to be returning 22 data but the code only returning 19 data
export const getHistoryList = async (filterPayload: Array<IFilterPayload>, dispatch: Dispatch<any>) => {
dispatch(setProductStart())
let payload: IHistoryList[] = [];
let filter: ModelImportHistoryFilterInput = {};
let orFilter: ModelImportHistoryFilterInput[] = [];
filterPayload.map((item) => {
if (item.type === "merchantID") {
filter = { ...filter, merchantImportHistoriesId: { eq: item.value } };
}
if (item.type === "action") {
orFilter.push({ action: { eq: ImportHistoryAction[item.value as keyof typeof ImportHistoryAction] } });
}
});
orFilter = orFilter.filter(item => item.action?.eq !== undefined);
if (orFilter.length > 0) {
filter = { ...filter, or: orFilter };
}
const result = await (API.graphql({
query: queriesCustom.listImportHistoriesCustom,
variables: { filter: filter }
}) as Promise<{ data?: any }>)
.then((response) => {
const data = response.data.listImportHistories.items;
return data
})
...
}
if i remove the filter from variables i got only 100 data from total 118 data
i already try this temporary solution to set the limit in variables to 2000, which is worked, but i don't think this is the correct approach
const result = await (API.graphql({
query: queriesCustom.listImportHistoriesCustom,
variables: { limit: 2000, filter: filter }
}) as Promise<{ data?: any }>)
.then((response) => {
const data = response.data.listImportHistories.items;
return data
})
how can i overcome this problem please help?

Providing two combined Reducers for my redux saga store prevents my websocket channel message from triggering, but only one does not?

Configured my store this way with redux toolkit for sure
const rootReducer = combineReducers({
someReducer,
systemsConfigs
});
const store = return configureStore({
devTools: true,
reducer: rootReducer ,
// middleware: [middleware, logger],
middleware: (getDefaultMiddleware) => getDefaultMiddleware({ thunk: false }).concat(middleware),
});
middleware.run(sagaRoot)
And thats my channel i am connecting to it
export function createSocketChannel(
productId: ProductId,
pair: string,
createSocket = () => new WebSocket('wss://somewebsocket')
) {
return eventChannel<SocketEvent>((emitter) => {
const socket_OrderBook = createSocket();
socket_OrderBook.addEventListener('open', () => {
emitter({
type: 'connection-established',
payload: true,
});
socket_OrderBook.send(
`subscribe-asdqwe`
);
});
socket_OrderBook.addEventListener('message', (event) => {
if (event.data?.includes('bids')) {
emitter({
type: 'message',
payload: JSON.parse(event.data),
});
//
}
});
socket_OrderBook.addEventListener('close', (event: any) => {
emitter(new SocketClosedByServer());
});
return () => {
if (socket_OrderBook.readyState === WebSocket.OPEN) {
socket_OrderBook.send(
`unsubscribe-order-book-${pair}`
);
}
if (socket_OrderBook.readyState === WebSocket.OPEN || socket_OrderBook.readyState === WebSocket.CONNECTING) {
socket_OrderBook.close();
}
};
}, buffers.expanding<SocketEvent>());
}
And here's how my saga connecting handlers looks like
export function* handleConnectingSocket(ctx: SagaContext) {
try {
const productId = yield select((state: State) => state.productId);
const requested_pair = yield select((state: State) => state.requested_pair);
if (ctx.socketChannel === null) {
ctx.socketChannel = yield call(createSocketChannel, productId, requested_pair);
}
//
const message: SocketEvent = yield take(ctx.socketChannel!);
if (message.type !== 'connection-established') {
throw new SocketUnexpectedResponseError();
}
yield put(connectedSocket());
} catch (error: any) {
reportError(error);
yield put(
disconnectedSocket({
reason: SocketStateReasons.BAD_CONNECTION,
})
);
}
}
export function* handleConnectedSocket(ctx: SagaContext) {
try {
while (true) {
if (ctx.socketChannel === null) {
break;
}
const events = yield flush(ctx.socketChannel);
const startedExecutingAt = performance.now();
if (Array.isArray(events)) {
const deltas = events.reduce(
(patch, event) => {
if (event.type === 'message') {
patch.bids.push(...event.payload.data?.bids);
patch.asks.push(...event.payload.data?.asks);
//
}
//
return patch;
},
{ bids: [], asks: [] } as SocketMessage
);
if (deltas.bids.length || deltas.asks.length) {
yield putResolve(receivedDeltas(deltas));
}
}
yield call(delayNextDispatch, startedExecutingAt);
}
} catch (error: any) {
reportError(error);
yield put(
disconnectedSocket({
reason: SocketStateReasons.UNKNOWN,
})
);
}
}
After Debugging I got the following:
The Thing is that when I Provide one Reducer to my store the channel works well and data is fetched where as when providing combinedReducers I am getting
an established connection from my handleConnectingSocket generator function
and an empty event array [] from
const events = yield flush(ctx.socketChannel) written in handleConnectedSocket
Tried to clarify as much as possible
ok so I start refactoring my typescript by changing the types, then saw all the places that break, there was a problem in my sagas.tsx.
Ping me if someone faced such an issue in the future

How to chain two GraphQL queries in sequence using Apollo Client

I am using Apollo Client for the frontend and Graphcool for the backend. There are two queries firstQuery and secondQuery that I want them to be called in sequence when the page opens. Here is the sample code (the definition of TestPage component is not listed here):
export default compose(
graphql(firstQuery, {
name: 'firstQuery'
}),
graphql(secondQuery, {
name: 'secondQuery' ,
options: (ownProps) => ({
variables: {
var1: *getValueFromFirstQuery*
}
})
})
)(withRouter(TestPage))
I need to get var1 in secondQuery from the result of firstQuery. How can I do that with Apollo Client and compose? Or is there any other way to do it? Thanks in advance.
The props added by your firstQuery component will be available to the component below (inside) it, so you can do something like:
export default compose(
graphql(firstQuery, {
name: 'firstQuery'
}),
graphql(secondQuery, {
name: 'secondQuery',
skip: ({ firstQuery }) => !firstQuery.data,
options: ({firstQuery}) => ({
variables: {
var1: firstQuery.data.someQuery.someValue
}
})
})
)(withRouter(TestPage))
Notice that we use skip to skip the second query unless we actually have data from the first query to work with.
Using the Query Component
If you're using the Query component, you can also utilize the skip property, although you also have the option to return something else (like null or a loading indicator) inside the first render props function:
<Query query={firstQuery}>
{({ data: { someQuery: { someValue } = {} } = {} }) => (
<Query
query={secondQuery}
variables={{var1: someValue}}
skip={someValue === undefined}
>
{({ data: secondQueryData }) => (
// your component here
)}
</Query>
Using the useQuery Hook
You can also use skip with the useQuery hook:
const { data: { someQuery: { someValue } = {} } = {} } = useQuery(firstQuery)
const variables = { var1: someValue }
const skip = someValue === undefined
const { data: secondQueryData } = useQuery(secondQuery, { variables, skip })
Mutations
Unlike queries, mutations involve specifically calling a function in order to trigger the request. This function returns a Promise that will resolve with the results of the mutation. That means, when working with mutations, you can simply chain the resulting Promises:
const [doA] = useMutation(MUTATION_A)
const [doB] = useMutation(MUTATION_B)
// elsewhere
const { data: { someValue } } = await doA()
const { data: { someResult } } = await doB({ variables: { someValue } })
For anyone using react apollo hooks the same approach works.
You can use two useQuery hooks and pass in the result of the first query into the skip option of the second,
example code:
const AlertToolbar = ({ alertUid }: AlertToolbarProps) => {
const authenticationToken = useSelectAuthenticationToken()
const { data: data1 } = useQuery<DataResponse>(query, {
skip: !authenticationToken,
variables: {
alertUid,
},
context: makeContext(authenticationToken),
})
const { data: data2, error: error2 } = useQuery<DataResponse2>(query2, {
skip:
!authenticationToken ||
!data1 ||
!data1.alertOverview ||
!data1.alertOverview.deviceId,
variables: {
deviceId:
data1 && data1.alertOverview ? data1.alertOverview.deviceId : null,
},
context: makeContext(authenticationToken),
})
if (error2 || !data2 || !data2.deviceById || !data2.deviceById.id) {
return null
}
const { deviceById: device } = data2
return (
<Toolbar>
...
// do some stuff here with data12

Redux reducer correct way to check if item already exists in state

I'm a little uncertain of this approach when updating an existing or adding a new object to a redux store but am having trouble getting this to work using the accepted methods i.e. Object.assign, update() or spread operators. I can get it working as follows:
const initialState = {
cart: []
}
export default function cartReducer(state = initialState, action) {
switch (action.type) {
case ADD_TO_CART:
let copy = _.clone(state.cart);
let cartitem = _.find(copy, function (item) {
return item.productId === action.payload.productId;
});
if (cartitem) {
cartitem.qty = action.payload.qty;
} else {
copy.push(action.payload);
}
return {
...state,
cart: copy
}
default:
return state
}
}
Although this works, I'm using Underscore to copy the state and check whether the item already exists in state which seems unnecessary and overkill?
This is the code for the redux. Use the .find function to find if an element is already in the array.
Example Code:
const inCart = state.cart.find((item) =>
item.id === action.payload.id ? true : false
);
return {
...state,
cart: inCart
? state.cart.map((item) =>
item.id === action.payload.id
? { ...item, qty: item.qty + 1 }
: item
)
: [...state.cart, { ...item, qty: 1 }],
};
With Redux-Toolkit you can mutate the state objects so you can likely simplify this a bit.
const basket = createSlice({
name: "cart",
initialState,
reducers: {
addToCart: (state, { payload }) => {
const inCart= state.cart.find((item) => item.id === payload.id);
if (inCart) {
item.qty += payload.qty;
} else {
state.items.push(payload);
}
},
},
});

Is there a way to user pairs for Rxjs5?

Can not find Rx.Observable.pairs in Rxjs5,
what I need just convert an object into Observable and inspect the change for each property.
any ideas?
var a = { aa: "aa", bb: "bb" };
function pairs(obj) {
// List of object's key-value pairs
var keyValuePairs = Object.keys(obj).map(key => ({ key, value: obj[key] }));
// Convert to an Observable and return
return Rx.Observable.from(keyValuePairs);
}
var xxx = pairs(a);
xxx.subscribe(x => {
console.log(x);
})
a.aa = "mm";
You can accomplish this from scratch:
function pairs(obj) {
// List of object's key-value pairs
var keyValuePairs = Object.keys(obj).map(key => ({ key, value: obj[key]}));
// Convert to an Observable and return
return Rx.Observable.from(keyValuePairs);
}

Resources