I'm trying to convert the following #ngrx effect to a redux-observable epic:
#Effect()
startReading$ =
this.actions$.ofType('START_READING').switchMap(() => {
return Observable.interval(200)
.takeUntil(
this.actions$.ofType('ABORT_PAGE_PROCESSING))
.mapTo({ type: 'PROCESS_PAGE' });
});
My attempt was to do:
export const startReadingEpic = action$ =>
action$
.ofType('START_READING')
.switchMap(() =>
Observable.interval(200)
.takeUntil(action$.ofType('ABORT_PAGE_PROCESSING'))
.mapTo({ type: 'PROCESS_PAGE' })
);
which doesn't seem to work. Returning a single Observable.of({ type: 'PROCESS_PAGE' }) works fine though.
Did I miss anything required by redux-observable that is handled out-of-the box by #ngrx ?
Thanks.
Code looks fine. It's just normal Rx, agnostic of redux-observable or ngrx (except for the ofType operator` but it's identical in both libraries)
Here it is, working:
https://jsbin.com/nosabuy/edit?js,output
There must be a problem somewhere else in your app. Check your console for errors, but if you don't see any you might try using "Pause on Caught Exceptions" in Chrome to see if maybe someone is swallowing an error silently. There's an outstanding RxJS bug where Rx itself may swallow errors and in the case of redux-observable it might affect you if there is an error in your reducers: https://github.com/redux-observable/redux-observable/issues/263. That said, I caution you not to immediately assume you're being bitten by this bug. Your debugger is your best friend here to confirm what's going on.
This section is just to bypass stackoverflow's validation which wouldn't let me submit jsbin link without code
// ignore this
Related
I'm using the cy.visit() command but the website i'm visiting (which i don't own) doesn't always fire the load event, although the content itself that i need for testing does appear on the website.
Despite the content appearing, since the load event is not fired sometimes (for some reason which i can't fix since i don't have ownership over this website), the cy.visit() command fails.
Is there a way to "force" it somehow, similar to how we can pass { force: true} for the cy.click() command?
Add the below to your cypress commands file
Cypress.Commands.add('forceVisit', url => {
cy.window().then(win => {
return win.open(url, '_self');
});
});
And in your tests, you can call
cy.forceVisit("www.google.com")
It's hard to simulate the problem, but I think I managed by setting pageLoadTimeout really low (30ms).
You can catch the onLoad fail in an event handler and checking for the page load error message.
I recommend doing it in a beforeEach().
beforeEach(() => {
Cypress.config("pageLoadTimeout", 30) // set this to whatever time length
// you feel is appropriate to start testing
// You'll need to experiment to get this right
// and in CI it will be a lot longer
cy.once('fail', (err) => { // "once" to just catch a single error
const message = err.parsedStack[0].message
if (message.match(/Timed out after waiting `\d+ms` for your remote page to load/)) {
return false
}
throw err // any other error, fail it
})
cy.visit('www.example.com');
})
it('checks the heading of the page', () => {
cy.get('h1').should('have.text', 'Example Domain') // ✅
})
As you can already assume, that is highly discouraged. It also really depends on how it fails and with which errors, but, without any code to reproduce, you may want to try this if you haven't already:
cy.visit('/', {failOnStatusCode: false});
Reference: https://docs.cypress.io/api/commands/visit#Arguments
I have an application that has a document section showing some notes and I am trying to identify and verify the text ("Release Notes") with Cypress. But all my locating strategies are failing and need some help. Please see if you can recommend some other way to locate this.
DOM:
Below is my code:
cy.get('.release-notes')
.should('be.visible')
.then((text => {
cy.log(text.text()) // blank
cy.log(text) // <span.release-notes>
}))
cy.get('[data="release-notes.html"]').should('be.visible').then((text => {
cy.log(text.text()) // blank
cy.log(text) // <object.release-notes-object>
}))
//Below lines - Fails
//cy.get('h1:contains("Release Notes")') -- Timed out retrying after 4000ms: Expected to find element: h1:contains("Release Notes"), but never found it.
//cy.get('body').should('contains', "Release Notes"); --Timed out retrying after 4000ms: object tested must be an array, a map, an object, a set, a string, or a weakset, but object given
Note: I have "includeShadowDom": true inside my cypress.json
You may be getting blocked by the #document. It does not look like an iframe, but may behave like one.
Try
cy.get('object.release-notes-object')
.its('0.contentDocument').should('exist')
.its('body').should('not.be.undefined').within(() => {
cy.get('h1').should('contain', 'Release Notes')
})
Also turn off chromeWebSecurity in case there's a cross-domain issue
cypress.json
{
"chromeWebSecurity": false
}
Debugging the inner document
Since you can get into the inner document body, in theory you should now be able to query it.
Take a look at the DOM inside body from Cypress' perspective, experiment with timing - the release notes likely to be fetched from a server
cy.get('object.release-notes-object')
.its('0.contentDocument').should('exist')
.its('body').should('not.be.undefined')
.then($body => {
cy.wait(10000) // just for debugging, explicit wait here
.then(() => console.log($body[0].innerHTML)) // inspect the elements inside after wait
})
Another way, add a .should() to retry
cy.wait(10000) // for debugging only, waiting for fetch
cy.get('object.release-notes-object')
.its('0.contentDocument').should('exist')
.its('body', {timeout: 10000}) //vary timeout here
.should('not.be.undefined')
.should('have.descendants', 'h1') // retries the body fetch until true
The difference between the last and adding a timeout to cy.get('h1') is that .should('have.descendants', 'h1') will re-query the body during each retry.
It's possible that there is an empty body element before the release notes are fetched, and it is replaced when the release notes are added.
Before the "includeShadowDom": true global flag we have to do something like this:
cy.get('selector').shadow().find('selector')
Now may be you can omit the .shadow() part and try
cy.get('[app-name="Voyage Planning"]').find('h1:contains("Release Notes")')
You have attributes data-gr-ext-installed and data-new-gr-c-s-check-loaded on the body. These look like they mark the end of something loading.
Add a check for that in #Mihi's solution (which must be nearly correct).
cy.get('object.release-notes-object')
.its('0.contentDocument').should('exist')
.its('body')
.should('not.be.undefined')
.should('have.attr', 'data-gr-ext-installed') // or data-new-gr-c-s-check-loaded
.within(() => {
cy.get('h1').should('contain', 'Release Notes')
})
I am trying to setup Qunit to test user actions like this:
QUnit.test( "Ran user search", function( assert ) {
assert.greaterThan($('#user-list .list li').length, 0, 'Number of results returned');
//setup user settings tests
var testUser = $('#user-list .list li').first();
testUser.find('.show-hide-more').trigger('click');
var testSettingsPanel = testUser.find('.show-more').first();
assert.equal(testSettingsPanel.css('display'), 'block', 'Settings panel should be openable');
});
The final assert fails because the display style is still none and not block. The click event should be changing it from none to block, and when I run the steps one by one in the console this is what happens, so my guess is there is a race condition happening in here. Anyone see what I need to change?
Edit
Adding this after the trigger:
console.log(testSettingsPanel.css('display'));
Gives me 'none', so there definitely seems to be a race condition or something going on. How can I overcome this?
Worked the issue out. Turns out what I thought was a simple toggle click was actually an ajax call, which I didn't recognise because I'm not yet familiar with the library.
This works fine:
var done = assert.async();
setTimeout(function() {
assert.equal(testSettingsPanel.css('display'), 'block', 'Settings panel should be openable');
done();
}, 1000);
I would like to use the onErrorResumeNext feature of RxJS, i.e. to continue to receive events even if an error is received (instead of terminating).
But I can see in the following doc that there is no correspondance in RxJS5: https://github.com/ReactiveX/RxJS/blob/master/MIGRATION.md.
Is there a workaround to use such feature?
Thanks!
I've been looking for that operator too! I came up with a solution for my needs that I hope will help yours. It's not the best solution most likely, but I hope it can help until a better solution can be found by some others on here, or until this operator is added back in 5.0 (hopefully!) :)
var Observable = Rx.Observable;
var source1 = Observable.create(function(observer){
observer.error();
});
var source2 = Observable.create(function(observer){
observer.next('Continuing on');
observer.complete();
});
var stream = source1.catch(function(data){
return source2;
});
stream.subscribe(function(data){
console.log(data);
});
JS Bin Example: https://jsbin.com/qadozoveta/edit?html,js,console
You can use the following in rxjs5 still.
Observable.onErrorResumeNext(observable1$, observable2$, observable3$...)
.subscribe(() => { ... })
onErrorResumeNext source code
Let me begin by saying that I'm on JQuery version 1.3.2. Upgrading at this point is not an option.
I have a form that is added in by a templating system after the page load occurs. I'm very new to JQuery but it's my understanding that live will allow me to access it.
The function for the autocomplete already serves a user search and works well. I want to share this function for the admin part of the site as well as the query is almost identically the same.
The clientName element is from the dynamically added form. If I use the code below, nothing happens; no data is retrieved.
$('#clientName')
.site_clientAutocomplete(
'admin',
function( $event, $result, $data )
{
$('#clientName').val($data.ClientName);
}
);
If I wrap it inside the following code, it will work, sort of. I have to click inside the input box several times before I can get anything back from the database.
$("#clientName").live('keydown', function(){
});
Can someone tell me how I can get this autocomplete to function properly?
live is just for handling events that occur on elements matching the selector now or in the future. If you need more robust detection of elements matching your selector, you can either apply the widget when the content is added, or you can use the livequery plugin
With livequery, you can "listen" for new elements matching your selector and run a function when that event occurs. In your case, this would go something like this:
$('clientName').livequery(function () {
$('#clientName').site_clientAutocomplete(
'admin',
function( $event, $result, $data )
{
$('#clientName').val($data.ClientName);
}
);
});