My question is simple. I am subscribe multiple publication in onCreated. How can I make in single line?
Template.Name.onCreated(() => {
Template.instance().subscribe('countries');
Template.instance().subscribe('pincode');
});
Something like
Template.Name.onCreated(() => {
Template.instance().subscribe(['countries','pincode']);
});
Maybe you wanna create a combined publication
Meteor.publish('combined', functinon() {
return [
Countries.find(),
Pincodes.find()
];
})
and then subscribe to that
Template.Name.onCreated(() => {
Meteor.subscribe('combined');
});
You could do this:
['countries','pincode'].forEach(x => {Template.instance().subscribe(x);});
Though I agree with #durrrr, there is not going to be any performance benefit. I'd leave it as two separate lines myself.
Related
I'm using Cypress to test a website.
When I use xpath inside cy.origin(), It's not working.
it('t1', function() {
cy.origin(('BaseUrl'), () => {
cy.visit('/profile')
cy.xpath("//input[#name='username']").type('user')
cy.xpath("//input[#name='password']").type('pass')
cy.xpath("//button[#type='button']").click()
})
})
Error:
TypeError
cy.xpath is not a function
Note that it works correctly outside cy.origin()
TLDR: Stick with standard Cypress commands inside cy.origin().
It's a current limitation of cy.orgin(), in fact any custom command must be treated specially and cy.xpath() is a custom command.
See Callback restrictions
It is also currently not possible to use require() or dynamic import() within the callback. Because of this limitation, it cannot use npm packages or other third-party libraries inside the callback, as there is no mechanism to reference them. This functionality will be provided in a future version of Cypress.
While third-party packages are strictly unavailable, it is possible to reuse your own code between cy.origin() callbacks. The workaround is to create a custom Cypress command within the secondary origin in a before block:
before(() => {
cy.origin('somesite.com', () => {
Cypress.Commands.add('clickLink', (label) => {
cy.get('a').contains(label).click()
})
})
})
it('clicks the secondary origin link', () => {
cy.origin('somesite.com', () => {
cy.visit('/page')
cy.clickLink('Click Me')
})
})
But you can't use this pattern with cy.xpath() as you currently need to require('cypress-xpath') and that can't be done inside cy.origin().
A Workaround
Navigate to /node_modules/cypress-xpath/src/index.js
Copy the entire contents
Add a new command file in support: /cypress/support/xpath.js
Add this to the file, pasting in the copied code
before(() => {
cy.origin('somesite.com', () => { // your cross-origin URL here
// paste here code from /node_modules/cypress-xpath/src/index.js
})
})
Import xpath.js into /cypress/support/commands.js
Now cy.xpath() will work within cy.orgin() in any of your tests.
Check to see if non-xpath works.
cy.origin(('BaseUrl'), () => {
cy.visit('/profile')
cy.get("input[#name='username']").type('user')
...
If not, you've probably not set the experimentalSessionAndOrigin flag correctly.
I want Cypress to go through every page to see on a website to see if there are any console errors and if so, make it known to the user running the test. (I'm thinking it would be useful for CSP checking to see if the site is throwing a console error because of a domain not being whitelisted.)
This package cypress-fail-on-console-error
may make it easier
test
import failOnConsoleError from 'cypress-fail-on-console-error';
failOnConsoleError();
const pages = [ "/page1", "/page2" ]
pages.forEach(page => {
it(`verifies the page ${page}`, () => {
cy.visit(page)
})
})
There's some interesting stuff on Cypress and CSP here
Testing Content-Security-Policy using Cypress ... Almost
You can use a combination of Cypress functionality to achieve this. You could store the list of links in an array of strings, use Cypress Lodash to iterate through each string as a separate test, and use the onBeforeLoad callback within cy.visit() to spy on console.error.
describe('Tests', () => {
// Define links
const links = ['/1', '/2', '/3'...]
// Iterate through the links array using Cypress Lodash
Cypress._.times(links.length, (index) => {
it('validates site loads with no errors', () => {
cy.visit(links[index], {
// set the `onBeforeLoad` callback to save errors as 'error'
onBeforeLoad(win) {
cy.stub(win.console, 'error').as('error');
}
});
// Validate error was not called
cy.get('#error').should('not.have.been.called');
});
});
});
A good deal of this answer was taken from this answer.
If you'd like to be specific about the errors that fail, try catching uncaught:exception
Cypress.on('uncaught:exception', (err) => {
if (err.message.includes('Content Security Policy')) {
return true
} else {
return false // only fail on the above message
}
})
describe('Testing Content Security Policy', () => {
const pages = [ "/page1", "/page2" ]
pages.forEach(page => {
it(`visiting page ${page}`, () => {
cy.visit(page)
})
})
})
I have the following problem with some implementation in React/Redux.
After clicking on a button, a specific redux action is call and div with notification shows on screen. You can close this notification by clicking on a (X) sign on that div (another redux action) or notification will close automatically after 5 secs. Clicking on (x) should cancell an automatic action.
actions:
const OPEN = 'show_notification';
const CLOSE = 'close_notification';
const CLOSE_AUTO = 'close_auto';
function showNotification(data) {
return {
type: 'OPEN',
data
}
}
function closeNotification(index) {
return {
type: 'CLOSE',
index
}
}
function closeAuto() {
return {
type: 'CLOSE_AUTO'
}
}
epics:
import (...)
closeNotificationAuto = action$ => action
.filter(action => action.type === OPEN)
.mergeMap(action => action
.delay(5000)
.map( () => closeAuto)
.takeUntil(action$.ofType(CLOSE))
}
Anyway, when two notifications are on screen, the action === CLOSE is closing the first one, and cancell delay() for another.
Not posting my whole code because the problem is here, in epics. Can't manage to achieve a solution:
when clicking on a (x) the specific notification is close, but another one (which time is for example 3secs) is still visible and hide automatically after another 2 secs.
Thans for any help!
The code in the epic is incomplete, so it's not totally clear (what happens inside the mergeMap?). But I did see one issue, which is that your takeUntil is on the top-level observable chain, which means it won't just cancel that particular delay, it will also stop listening for any action at all.
Instead, you need to delay and cancel the matched action individually inside something like a mergeMap, switchMap, etc. This is commonly called "isolating your observer chains".
Here's what that might look like:
const closeNotificationAuto = action$ =>
action$
.ofType(OPEN)
.mergeMap(action =>
Observable.of(action)
.delay(5000)
.map(() => closeAuto())
.takeUntil(action$.ofType(CLOSE))
);
This pattern, filter then flatMap (mergeMap, switchMap, etc), is how most of your epics will look.
Regarding your comments below, it sounds like you want to add a filter to takeUntil notifier to only take CLOSE actions that somehow uniquely identifies it.
See https://stackoverflow.com/a/48452283/1770633
const closeNotificationAuto = action$ =>
action$
.ofType(OPEN)
.mergeMap(action =>
Observable.of(action)
.delay(5000)
.map(() => closeAuto())
.takeUntil(
action$.ofType(CLOSE).filter(a => a.something === action.something)
)
);
If there isn't some sort of unique ID already available for each, you'll need to create and include one.
My Meteor app runs slowly in the beginning for about ten seconds, and then becomes fast again. I am trying to improve the performance but having troubles to find the real cause.
I thought the problem was that I am publishing all the course information like following:
if (Meteor.isServer) {
Meteor.publish("courses", function() {
return Courses.find();
});
}
I tried using Kadira to monitor exactly what's happening. However, looking at the result, I am starting to think maybe it's not the real problem.
If it only takes 292ms for pubsub response time, it shouldn't feel that laggy but I cannot think of any other reason why the app would be so slow in the beginning and become fast again. Can an expert point me to the redirection?
UPDATE:
I could improve the duration of lagginess in the beginning by making the following changes:
in /server/publications.js
if (Meteor.isServer) {
Meteor.publish("courses", function() {
// since we only need these two fields for the search bar's autocomplete feature
return Courses.find({}, {fields: {'catalog':1, 'titleLong':1}});
});
Meteor.publish("courseCatalog", function(catalog) {
// publish specific information only when needed
return Courses.find({"catalog": catalog});
});
}
and in router.js I made changes accordingly so I subscribe based on specific pages. But there's still some lag in the beginning and I wonder if I can make more optimizations, and what is the real cause of the slowness in the beginning.
UPDATE2:
I followed the suggestion and made changes like below:
Session.set('coursesReady', false); on startup.
and in router:
Router.route('/', function () {
Meteor.subscribe("courses", function(err) {
if (!err) {
console.log("course data is ready")
Session.set('coursesReady', true);
}
});
....
and in /lib/helpers.js which returns data for typeahead library
if (Meteor.isClient) {
Template.registerHelper("course_data", function() {
console.log("course_data helper is called");
if (Session.get('coursesReady')) {
var courses = Courses.find().fetch();
return [
{
name: 'course-info1',
valueKey: 'titleLong',
local: function() {
return Courses.find().fetch();
},
template: 'Course'
},
But now the problem is that when the helper function is called, the data is never ready. The console print:
Q: How do I ensure that the helper function is called only after the data is ready, OR called again when the data is ready? Since Session is reactive, shouldn't it be called again automatically?
I can't check this right now, but I believe your issue might be that the course_data helper is being run multiple times before all 1000+ documents in the subscription are ready, causing the typeahead package to re-run some expensive calculations. Try something like this:
/client/views/global/helpers.js
Template.registerHelper("course_data", function() {
if (!Session.get('coursesReady')) return [];
return [ //...
/client/subscriptions.js
Meteor.subscribe("courses", function(error) {
if (!error) Session.set('coursesReady', true);
});
Update:
Really, Meteor's new features this.subscribe() and Template.instance().subscriptionsReady() are ideal for this. Session isn't really the right choice, but it should still be reactively updating (not sure why it isn't for you). Try instead making the following changes to /client/views/navwithsearch.js (and main, though ideally both templates should share a single search template):
Template.NavWithSearch.onCreated(function() {
this.subscribe('courses');
});
Template.NavWithSearch.onRendered(function() {
this.autorun(function() {
if (Template.instance().subscriptionsReady()) {
Meteor.typeahead.inject();
}
});
});
The idea is to tie the lifecycle of the subscription to the view that will actually be using that subscription. This should delay the typeahead injection until the subscription is completely ready.
I'm trying to set up a Master/Detail grid using the Grid control from Telerik's Extensions for ASP.NET MVC. My problem is setting up the server template.
The demo I'm following is the first one on this page, except I'm using Razor View Engine.
I have the grid displaying fine. The problem is that I cannot write any sort of a server template that doesn't throw a compiler error - aside from leaving it blank!
#(Html.Telerik().Grid(Model)
.Name("Grid")
.Columns(columns =>
{
columns.Bound(o => o.Date).Format("{0:MM/dd/yyyy}").Width(100);
columns.Bound(o => o.Title).Template(#<text> #item.Title</text>).Sortable(false);
columns.Bound(o => o.Publication).Width(120).Sortable(false);
})
.DetailView(detailView => detailView.Template(e =>
{
//Anything other than this comment will throw a compiler error
}))
.RowAction(row =>
{
// Expand initially the detail view of the first row
if (row.Index == 0)
{
row.DetailRow.Expanded = true;
}
})
.Sortable()
.Scrollable(scrolling => scrolling.Height(494)).Footer(false)
.ClientEvents(events => events.OnRowDataBound("onRowDataBound"))
)
See that comment "anything other than this comment..."? When I replace that with something like #<text> hello</text>, I get a compilation error:
CS1002: ; expected
That doesn't seem to make sense, but I humour myself and put a semicolon in like such #<text> hello</text>;. That gives me this error:
CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
When I replace that with a portion of the template I really want, namely #<text><b>Slug</b>: #item.Slug</text>, I get the same errors; CS1002 with no semicolon, and CS0201 with a semicolon.
What am I missing here?
There are two ways you can approach this. If you just want to display some simple text and not really integrate any other components it would be the easiest to modify the code you have above to just do this:
.DetailView(detailView => detailView.Template(#<text>test</text>))
As you can see I removed the whole e => { ... } part and just put in #<text></text>.
However, if you want to look into getting more components in your detail view I think it would be better to look at the demo found here. Although the description mentions some WebForms code you don't need to worry, the rest is all in Razor :) It also explains things you have to keep in mind. One of the most important ones is that any components within the DetailTemplate will have to use { ... } as opposed to ( ... ) this is because you want to specifically call .Render(); (using the ( ... ) implicitly calls .Render but at the wrong point for these scenarios) at the end of those components' declaration to make sure they are all rendered correctly.