Ngrx-effect doesn't sending payload in action on iOS - ios

For some time I have been trying to find a solution to my problem, however, nothing has worked so far. I'm working on Ionic 4 application with Angular 8 and Ngrx. I created #Effect that calling a service which calling http service and then I need to dispatch two actions. One of them have a payload also.
Everything working fine in development (browsers). I've tried on Chrome, Firefox, Safari. Problem is appearing when I'm trying on the iPhone. On the iPhone payload sending to action is empty object {} instead of object with proper fields.
I've tried to build in non-production mode, disabling aot, build-optimizer, optimization.
Store init:
StoreModule.forFeature('rental', reducer),
EffectsModule.forFeature([RentalServiceEffect]),
Store:
export interface Contract {
address: string;
identity: string;
endRentSignature?: string;
}
export interface RentalStoreState {
status: RentStatus;
contract?: Contract;
metadata?: RentalMetadata;
summary?: RentalSummary;
carState?: CarState;
}
export const initialState: RentalStoreState = {
status: RentStatus.NOT_STARTED,
contract: {
address: null,
identity: null,
endRentSignature: null,
},
};
Action:
export const rentVerified = createAction(
'[RENTAL] RENT_VERIFIED',
(payload: Contract) => ({ payload })
);
Reducer:
const rentalReducer = createReducer(
initialState,
on(RentActions.rentVerified, (state, { payload }) => ({
...state,
contract: payload,
status: RentStatus.RENT_VERIFIED
})));
export function reducer(state: RentalStoreState | undefined, action: Action) {
return rentalReducer(state, action);
}
Method from a service:
public startRentalProcedure(
vehicle: Vehicle,
loading: any
): Observable<IRentalStartResponse> {
loading.present();
return new Observable(observe => {
const id = '';
const key = this.walletService.getActiveAccountId();
this.fleetNodeSrv
.startRent(id, key, vehicle.id)
.subscribe(
res => {
loading.dismiss();
observe.next(res);
observe.complete();
},
err => {
loading.dismiss();
observe.error(err);
observe.complete();
}
);
});
}
Problematic effect:
#Effect()
public startRentalProcedure$ = this.actions$.pipe(
ofType(RentalActions.startRentVerifying),
switchMap(action => {
return this.rentalSrv
.startRentalProcedure(action.vehicle, action.loading)
.pipe(
mergeMap(response => {
return [
RentalActions.rentVerified({
address: response.address,
identity: response.identity
}),
MainActions.rentalProcedureStarted()
];
}),
catchError(err => {
this.showConfirmationError(err);
return of({ type: '[RENTAL] START_RENTAL_FAILED' });
})
);
})
);

Related

Jest Twilio Mock

I would like to know how do I mock a Twilio function inside a lib.
I need help taking the test
If anyone has any ideas thanks
I have this method:
joinSession(data: ICallConfig) {
const token = data.providerData.Token.toString();
this._sessionId = data.sessionId;
this._localConnectionId = data.providerData.CustomerId;
const videoCallOptions = {
name: data.providerData.RoomName,
tracks: this._stream.getTracks(),
};
try {
this._room = await connect(token, videoCallOptions);
} catch (e) {
console.log('Twilio video error: ' + e);
}
I need to mock twilio's connect() function
My test:
describe('joinSession', () => {
test('connect user in room', () => {
// Create object
const data: ICallConfig = {
providerData: {
Token: '',
CustomerId: '',
RoomName: 'Room Test',
},
sessionId: '',
};
mockMediaStream.addTrack(new MockTrack('audio'));
mockMediaStream.addTrack(new MockTrack('video'));
twilioService.setMediaStream(mockMediaStream);
twilioService.joinSession(data);
});

Relay Modern updater ConnectionHandler.getConnection() returns undefined when parent record is root

Debugging update:
So, we went a bit further in debugging this and it seems like 'client:root' cannot access the connection at all by itself.
To debug the complete store, we added this line in the updater function after exporting the store variable from the relay/environment.
console.log(relayEnvStore.getSource().toJSON())
If I use .get() with the specific string client:root:__ItemList_items_connection, I can access the records I have been looking for but it's definitely not pretty.
const testStore = store.get('client:root:__ItemList_items_connection')
console.log(testStore.getLinkedRecords('edges'))
Original:
I'm using Relay Modern and trying to update the cache after the updateItem mutation is completed with the updater. The call to ConnectionHandler.getConnection('client:root', 'ItemList_items') returns undefined.
I'm not sure if it's because I'm trying to use 'client:root' as my parent record or if there's a problem with my code. Has anyone found themselves with a similar issue?
Here's the paginationContainer:
const ItemListPaginationContainer = createPaginationContainer(
ItemList,
{
node: graphql`
fragment ItemList_node on Query
#argumentDefinitions(count: { type: "Int", defaultValue: 3 }, cursor: { type: "String" }) {
items(first: $count, after: $cursor) #connection(key: "ItemList_items") {
edges {
cursor
node {
id
name
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
`
},
{
direction: 'forward',
getConnectionFromProps: props => props.node && props.node.items,
getVariables(props, { count, cursor }) {
return {
count,
cursor
}
},
query: graphql`
query ItemListQuery($count: Int!, $cursor: String) {
...ItemList_node #arguments(count: $count, cursor: $cursor)
}
`
}
)
Here's the mutation:
const mutation = graphql`
mutation UpdateItemMutation($id: ID!, $name: String) {
updateItem(id: $id, name: $name) {
id
name
}
}
`
Here's the updater:
updater: (store) => {
const root = store.getRoot()
const conn = ConnectionHandler.getConnection(
root, // parent record
'ItemList_items' // connection key
)
console.log(conn)
},
Turns out that I was setting my environment incorrectly. The store would reset itself every time I would make a query or a mutation, hence why I couldn't access any of the connections. I initially had the following:
export default server => {
return new Environment({
network: network(server),
store: new Store(new RecordSource())
})
}
All connections are accessible with this change:
const storeObject = new Store(new RecordSource())
export default server => {
return new Environment({
network: network(server),
store: storeObject
})
}

Angular 7 Cannot read property 'map' of undefined

I'm having this problem to use mat-autocomplete async, I have tried several solutions mainly from here and even then I did not succeed. follow my code ... Thanks
component.ts
filteredEmpresas: Observable<IEmpresaResponse>;
empresasForm: FormGroup;
this.empresasForm = this.fb.group({
empresaInput: null
})
this.filteredEmpresas = this.empresasForm.get('empresaInput').valueChanges
.pipe(
debounceTime(300),
switchMap(value => this.appService.search({text: value}, 1))
);
service.ts
search(filter: {text: string} = {text: ''}, page = 1):
Observable<IEmpresaResponse> {
return this.http.get<IEmpresaResponse>(this.apiURL + '/busca/'+filter.text)
.pipe(
tap((response: IEmpresaResponse) => {
response.results = response.results
.map(empresa => new Empresa(empresa.idEmpresa, empresa.nomeEmpresa, empresa.ativo));
return response;
})
);
}
class.ts
export class Empresa {
constructor(public idEmpresa: number, public nomeEmpresa: string, public ativo: Boolean) {}
}
export interface IEmpresaResponse {
total: number;
results: Empresa[];
}

sessionConfig.perform not being called

I am trying to write a session authentication mechanism for my application, which goes like that:
import { ZObject, Bundle } from "zapier-platform-core";
import IAuthenticationScheme from "../interfaces/authentication/IAuthenticationScheme";
const getSessionKey = (z: ZObject, bundle: Bundle) => {
console.log('GET SESSION called');
const { username: auth_login, password: auth_password } = bundle.authData;
return z.request({
method: 'POST',
url: 'http://******/perl/auth/login',
body: { auth_login, auth_password }
}).then(response => {
z.console.log(response);
console.log(response);
if (response.status === 401) {
throw new Error('The username/password you supplied is invalid');
} else {
return {
sessionKey: z.JSON.parse(response.content).session_id
};
}
});
};
const includeSessionKeyHeader = (request: any, z: ZObject, bundle: Bundle) => {
console.log('includeSessionKeyHeader called');
if (bundle.authData.sessionKey) {
request.headers = Object.assign({}, request.headers);
let { Cookie: cookie = '' } = request.headers;
cookie = `${bundle.authData.sessionKey};${cookie}`;
request.headers['Cookie'] = cookie;
}
return request;
};
const sessionRefreshIf401 = (response: any, z: ZObject, bundle: Bundle) => {
console.warn('sessionRefreshIf401 called');
if (bundle.authData.sessionKey) {
if (response.status === 401) {
throw new z.errors.RefreshAuthError(); // ask for a refresh & retry
}
}
return response;
};
const test = (z: ZObject, bundle: Bundle) => {
console.log('test called');
return z.request({
url: 'http://******/ruby/features'
}).then((response) => {
z.console.log(response);
if (response.status === 401) {
throw new Error('The API Key you supplied is invalid');
}
return response
});
};
const authentication: IAuthenticationScheme<any> = {
type: 'session',
test,
fields: [
{
key: 'username',
type: 'string',
required: true,
helpText: 'Your login username.'
},
{
key: 'password',
type: 'string',
required: true,
helpText: 'Your login password.'
}
],
connectionLabel: (z, bundle) => {
return bundle.inputData.username;
},
sessionConfig: {
perform: getSessionKey
}
};
export default {
authentication,
beforeRequest: { includeSessionKeyHeader },
afterRequest: { sessionRefreshIf401 }
};
As you can see, I put console.log markers at the beginning of each function here so I can see in which order they are getting called.
Here is my test configuration:
import { should } from "should";
import { describe } from "mocha";
const { version } = require("../../package.json");
import { version as platformVersion } from "zapier-platform-core";
import { createAppTester } from "zapier-platform-core";
import PlackSession from "../authentication/PlackSession";
const App = {
version,
platformVersion,
authentication: PlackSession.authentication,
beforeRequest: [PlackSession.beforeRequest.includeSessionKeyHeader],
afterResponse: [PlackSession.afterRequest.sessionRefreshIf401],
};
const appTester = createAppTester(App);
export default () => {
describe('PlackSession authentication', () => {
it('should authenticate', done => {
console.log(`AUTHENTICATE!!`)
const bundle = {
authData: {
username: 'dev#******.com',
password: 'abc123'
}
};
appTester(App.authentication.test, bundle)
.then(response => {
console.log('BBBBBBBB')
done();
})
.catch(a => {
console.log('CCCCCC');
done(a)
});
});
});
};
And I can see the test output the logs in the following order:
authentication
PlackSession authentication
AUTHENTICATE!!
test called
includeSessionKeyHeader called
CCCCCC
1) should authenticate
That means sessionConfig.perform (getSessionKey) is never called, and this is where the credentials should be exchanged for authentication through the login API call, which I can also see in my server logs it never gets called, it skips straight to the test call and fails.
David here, from the Zapier Platform team. Great question!
I think the problem lies in your test. There should be two function. One should call App.authentication.sessionConfig.perform and tests exchanging username & password for a token. Another should call App.authentication.test, which tests fetching a protected resource with a valid key. Though these may be able to be chained together, they can also be written separately.
There's a more complete example here: https://github.com/zapier/zapier-platform-example-app-session-auth/blob/cc63ca67cbc8933439577b2362d026ba2a701e36/test/basic.js

Apollo Subscription doesn't seem to get called on Mutation

New to Apollo, so I decided to take the most simple example I found and try to work it in a slightly different way. My code can be found here.
The problem I am having is that the Subscription doesn't seem to get called when I call the Mutation createTask(). The Mutation and Subscription are defined in schema.graphql as:
type Mutation {
createTask(
text: String!
): Task
}
type Subscription {
taskCreated: Task
}
And in resolvers.js as:
Mutation: {
createTask(_, { text }) {
const task = { id: nextTaskId(), text, isComplete: false };
tasks.push(task);
pubsub.publish('taskCreated', task);
return task;
},
},
Subscription: {
taskCreated(task) {
console.log(`Subscript called for new task ID ${task.id}`);
return task;
},
},
What I am expecting to happen is that I would get a console.log in the server every time I run the following in the client:
mutation Mutation($text: String!) {
createTask(text:$text) {
id
text
isComplete
}
}
But nothing happens. What am I missing?
The subscription resolver function is called when there is actually a subscription to the GraphQL Subscription.
As you did not add a client which uses subscriptions-transport-ws and the SubscriptionClient for subscribing to your websocket and the subscription it will not work.
What you could do is add the subscription Channel to the setupFunctions of the SubscriptionManager and therein you get the value that the pubsub.publish function delivers.
Could look like this:
...
const WS_PORT = 8080;
const websocketServer = createServer((request, response) => {
response.writeHead(404);
response.end();
});
websocketServer.listen(WS_PORT, () => console.log( // eslint-disable-line no-console
`Websocket Server is now running on http://localhost:${WS_PORT}`
));
const subscriptionManager = new SubscriptionManager({
schema: executableSchema,
pubsub: pubsub,
setupFunctions: testRunChanged: (options, args) => {
return {
taskCreated: {
filter: (task) => {
console.log(task); // sould be log when the pubsub is called
return true;
}
},
};
},
,
});
subscriptionServer = new SubscriptionServer({
subscriptionManager: subscriptionManager
}, {
server: websocketServer,
path: '/',
});
...

Resources