How to undo `Arg.Do<T>(() => {})` in NSubstitute - nsubstitute

I've got this code:
sub.Foo(Arg.Do<int>(() => {}));
How do I undo this?
.ClearReceivedCalls() and .ClearReturnValues() seem to have no effect on removing this delegate

There isn't currently a way to remove the action, but you can queue it up in different ways that will allow you to stop it running.
The first option is to use an external action, then change that at a later point in time.
// Clear action manually
Action<string> action = x => SideEffect();
sub.Foo(Arg.Do<string>(x => action(x)));
// ...
action = x => { };
A variant of that approach can let you modify the action to automatically clear itself (alternatively we could use a guard clause to make sure it only runs the required amount of times):
// Self-clearing action (run once):
Action<string> action = x =>
{
SideEffect();
action = _ => { };
};
sub.Foo(Arg.Do<string>(x => action(x)));
Another option is to use the Callback builder. This is works with When..Do rather than Arg.Do, but does give you a bit of control over how different sequences of actions can be queued up (see the documentation for a more involved example):
// Callback builder:
// (See )
sub.When(x => x.Foo(Arg.Any<string>()))
.Do(Callback.First(call => SideEffect()));

Related

How could I do not repeat the selection process in Cypress?

How could I do not repeat the selection process in Cypress?
E.g. if I have:
cy
.get("...").find("...")...eq(0)...should("...")
.get("...").find("...")...eq(1)...should("...");
How could I avoid duplicating the .get("...").find("...")... part if at some point I need to pick either the eq(0) or the eq(1)?
You can use .as() to alias an element.
// Just aliasing the base
cy.get('foo').find('bar').as('something');
cy.get('#something').eq(0).should('exist');
cy.get('#something').eq(1).should('exist');
// aliasing the specific elements
cy.get('foo').find('bar').eq(0).as('firstEl');
cy.get('#firstEl').should('exist');
cy.get('foo').find('bar').eq(1).as('secondEl');
cy.get('#secondEl').should('exist');
You could also use a custom command.
// If the selectors in `get` and `find` are constant, you could do a custom command
Cypress.Commands.add('myGet', (index) => {
return cy.get('foo').find('bar').eq(index);
})
cy.myGet(0).should('exist');
// Or if you wanted to be able to customize the get and find
Cypress.Commands.add('myGet', (get, find, index) => {
return cy.get(get).find(find).eq(index);
})
cy.myGet('foo', 'bar', 0).should('exist');
You can create a custom command for this. Go to cypress/support/commands.js and write:
Cypress.Commands.add('selectElement', (index) => {
cy.get('selector').find('selector').eq(index).should('be.visible')
})
And then in your test just write:
cy.selectElement(1)
cy.selectElement(2)

Understanding then() in Cypress

I am reading through the documentation in Cypress and I think I have an idea as to what then() does. It works like promises, where a promise returns another promise, but with then(), we are returning a new subject.
If we look at the code example below, we are using then() because we are returning a new variable, which in this case is called target.
Am I understanding this correctly? If not, can someone correct me?
it.only('Marks an incomplete item complete', () => {
//we'll need a route to stub the api call that updates our item
cy.fixture('todos')
.then(todos => {
//target is a single todo, taken from the head of the array. We can use this to define our route
const target = Cypress._.head(todos)
cy.route(
"PUT",
`api/todos/${target.id}`,
//Here we are mergin original item with an object literal
Cypress._.merge(target, {isComplete: true})
)
})
.then is used to receive the results from cy.fixture('todos'). The variable target is not significant in this code.
In your code sample, the variable that is returned from cy.fixture is named todos - the spacing of the code may be throwing you off here? The .then call is attached to the cy.fixture() call
// These 2 code blocks are the same - just different spacing
cy.fixture('todos')
.then(todos => {});
cy.fixture('todos').then(todos => {});
https://docs.cypress.io/api/commands/fixture.html#Usage
cy.fixture('logo.png').then((logo) => {
// load data from logo.png
})
Using .then() allows you to use the yielded subject in a callback function and should be used when you need to manipulate some values or do some actions.
To put it simply, it is used to play around with the yield of the previous command and work around with it in that case. THEN() command is handy and helpful in debugging the yield of the previous command.
const baseURL = "https://jsonplaceholder.typicode.com";
describe("Get Call-Expect+ normal req", () => {
it("GetPostById-Expect", () => {
cy.request(baseURL + "/posts/1").as("GetPostById");
cy.get("#GetPostById").then((response) => {
//response: status
expect(response.status).to.equal(200);
expect(response.status).to.eq(200);
});
});
Refer: https://docs.cypress.io/api/commands/then#Promises

Why does Parse LiveQuery not always trigger update/create/enter event?

I am trying to achieve a board that enables real-time editing for cooperating users. I am running a parse server using Sashido, where I have LiveQueries enabled for among other things 'Sticky'. For the frontend I have the following code:
const query = new Parse.Query(Sticky);
... some query constraints
this.subscription = await query.subscribe();
this.subscription.on('open', () => {
console.log('SUBSCRIPTION: opened');
}
this.subscription.on('create', (sticky) => {
console.log('SUBSCRIPTION: created');
}
this.subscription.on('update', (sticky) => {
console.log('SUBSCRIPTION: updated');
}
this.subscription.on('enter', (sticky) => {
console.log('SUBSCRIPTION: entered');
}
this.stickies = await query.find();
When I open my application in two different browser tabs, I get the 'SUBSCRIPTION: opened'. When I edit or create Sticky instances, I expect to get the corresponding events and see changes in the Sashido database.
However, I always see the changes in the database, but half of the times when I create or edit Sticky instances, I do not get the update/create/enter events. Note: Sometimes they do get triggered, but I have not found a sequence of events that leads to them being triggered or not, it seems to happen at random.
Can someone see what I'm doing wrong?

Aurelia - Custom validation to check if a form has changes

I see THIS question regarding whether the form I am validating has changed.
However it has nothing to do with Aurelia validation and I would like to validate whether the form has any changes upon clicking the save button. I dont want to do it on the server.
What I have done is to save the values I fetched initially so I can do a comparison.
fetch("/api/Client/editClient/" + parms.id, {
method: "GET",
headers
})
.then(response => response.json())
.then(data => {
this.client.deserialize(data);
this.originalClient === this.client;
})
original client is the unmodified object.
I have created a custom validation function however its not working as intended.
I thought I could use the current value and then compare it to the original value.
ValidationRules.customRule(
'changesExist',
(value, obj, fetchedEntity) =>
fetchedEntity != value,
'No changes detected'
);
When I try and use it I find it erroring:
// Validation Rules.
ValidationRules
.ensure(a: ClientDetails) => a).satisfiesRule('changesExist', this.originalClient);
I am unsure how to make this work. What I want is a validation that compares the orginalClient object with the the one that is to be sent back to the server. This way I can check if there is reason for sending it back can saving it to the database...
It's rather brute force, but this will likely do what you want:
JSON.stringify(fetchedEntity) !== JSON.stringify(value)
The app-contacts sample app does it using an areEqual function. Have a look at the repo and you can see how it's used and how you could adapt it for your purposes.
function areEqual(obj1, obj2) {
return Object.keys(obj1).every((key) => obj2.hasOwnProperty(key) && (obj1[key] === obj2[key]));
};

How to populate the store and sequentially await return using Redux Observable?

I am attempting to use Redux Observable to call an action to fetch some data, wait for its return, then fetch some more data that relies on it.
I have an epic which populates a store from a fetch FetchTodos. This listens for the FETCH_TODOS action and then calls my todos API and populates {todos: [] } =
I also have a comments section in my store todoComments. However, I would like to only populate todoComments once FETCH_TODOS has returned and populated the store.
In imperative code, this might look like:
let todos = await api.get('/todos');
await dispatch("FETCH_TODO_COMPLETE", todos)
let firstId = getState().todos[0].id
let comments = await api.get(`/todos/${firstId}/comments')
await dispatch("FETCH_COMMENTS_COMPLETE", { todo_id: firstId, comments})
The closest I saw to this was this issue in the Redux Observable Repo, but I could not understand how to do this efficiently. This is a pretty common scenario for me.
I would like to reuse as much code as possible. In this example, I may dispatch FETCH_TODOS from multiple components.
How would i accomplish this with Redux-Observable?
Based on our conversation in the comments:
In redux-observable, you can sequence things in numerous ways. You could do it all in one epic using normal RxJS, or you could split them into multiple ones. If you split them, the subsequent epic would listen for the signal that the previous one has completed its task. Something like this:
// this assumes you make your `api.get` helper return an Observable
// instead of a Promise which is highly advisable.
// If it doesn't, you could do:
// Observable.from(api.get('/url'))
// but Promises are not truly cancellable which can cause max
// concurrent connections issues
const fetchTodosEpic = action$ =>
action$.ofType('FETCH_TODOS')
.switchMap(() =>
api.get('/todos')
.map(todos => ({
type: 'FETCH_TODOS_COMPLETE',
todos
}))
);
const fetchComments = action$ =>
action$.ofType('FETCH_TODOS_COMPLETE')
.switchMap(({ todos }) =>
api.get(`/todos/${todos[0].id}/comments`)
.map(comments => ({
type: 'FETCH_COMMENTS_COMPLETE',
comments
}))
);