A Meteor server code needs to run on the first second of every months "billing system". What would be a light weigh efficient way to go about it?
1)vsivsi:job-collection
2)percolate:synced-cron
Seam to be over kill. Any suggestion? thx
if you're using percolate:synced-cron, then somewhere on the server, you would run code that looks like this.
import {Meteor} from 'meteor/meteor';
Meteor.startup(() => {
SyncedCron.add({
name: 'Do Billing Task',
schedule: function(parser) {
return parser.text('on the first day of the month');
},
job: function() {
DoBillingTask();
}
});
SyncedCron.start();
});
cron itself is lightweight and is suited to the task you describe.
for the text, "on the first day of the month", i picked something that sounds like it would fit your needs. but that parser package has a lot of flexibility, you can read about it here:
http://bunkat.github.io/later/parsers.html#cron
Related
I am running a test suite (test1, test2, test3) in Cypress. I noticed when I run this suite for the first time, they all pass. On the next test run, they fail. It seems that it is failing because the data from test3 has not been removed from the cypress browser when test1 begins to run. Could this be a load issue or would adding a logout command at the end of each test case be the solution? Not sure what would be the solution for this.
It seems that it is failing because the data from test3 has not been removed from the cypress browser. First step is to find out where that data being stored ex: cookie, session storage or local storage? Once you found it, you can choose appropriate method to delete data. Incase you are interested in clearing all u can do something as below
beforeEach(() => {
cy.window().then(win => win.sessionStorage.clear());
cy.clearCookies();
cy.clearLocalStorage();
});
Make sure above syntax is correct from cypress.io.
In your support/index.js or support/index.ts file, you could have a call to before(() => {} that loads your browser up once, and then have all of your tests run in one browser session. When you run the tests again, the first thing it will do is reload the page in the browser so that you have a clean session to start from.
Have you tried adding a step to clear the cookies?
Cypress.Commands.add('logout', () => {
cy.clearCookies().then(() => {
cy.getCookies().should('be.empty').visit('/')
})
});
I see 2 solutions:
I. Add an assertion for the logout command - usualy adding an assertion solves this problem.
Cypress.Commands.add("shopFE_logout", (domain) => {
cy.log('shopFE_logout - start')
cy.get('[data-qa="logoutButton"]')
.click({ force: true })
.should('not.exist')
cy.log('shopFE_logout - end')
})
II. The more secure, but not popular way - separate the test cases to be 1 per file and organize them in folders
I found this on cypress docs "Remember, Cypress already automatically clears localStorage, cookies, sessions, etc before each test. Make sure you are not trying to clean up state that is already cleaned up by Cypress automatically."
https://docs.cypress.io/guides/references/best-practices.html#Is-resetting-the-state-necessary.
I don't think adding logout before each test will be a good idea.
In my test, I do login before each test and I have not done logout and still working fine
describe('This is my test suite', () => {
let credential = "";
beforeEach(function () {
cy.visit(Cypress.env('devUrl'));
cy.fixture('data/common/loginData.json').then(loginData => {
credential = loginData;
});
})
it('This is my first testcase', () => {
cy.myLoginCommand(credential.valid.username, credential.valid.password)
objLocation.navToLocationPage()
objLocation.verifySuccessMsg('Successfully Saved')
})
it('This is my second testcase', () => {
cy.myLoginCommand(credential.valid.username, credential.valid.password)
objLocation.navToLocationPage()
objLocation.verifySuccessMsg('Successfully Updated')
})
})
Here is the scenario:
I'm logging to my application by visiting app.domain/login (example) which will redirect me to something like another.app.domain/
This is working fine. But when I logout: cy.contains('logout').click(), I am getting
CypressError: Timed out after waiting '60000ms' for your remote page to load.
Any suggestions to get around this issue? Ps: I just started to learn Cypress and I want to logout mainly because I want to restore the state back.. I don't want my environment to be updated/modified with the automation scripts. Thanks in advance.
First of all, in cypress there is no AfterAll hook, so we have to use more handmade solution. Second think: if you want to use cypress instead of curl to clean up after test is ok (but I recommend us curl ;)).
First you need to add line to scripts section in package.json:
{
"scripts": {
"after-cypress": "cypress run --spec cypress/hooks/after-all.js",
}
}
File cypress/hooks/after-all.js should looks like this:
describe('clean up after test', () => {
before(() => {
cy.login() // Should we save auth token here?
});
it('', () => {
cy
.request()
.request()
.request() // each of request should delete created during test data
});
});
When I press the "run all specs" button or use the run command that runs all files in Cypress it runs all test files alphabetically, so I don't want that.
I want to sort all of them with my own rules.
Let's say I have 3 steps in a chat app test.
Can connect the chat app
Can connect the chat
Can the user send a message
I want to test every step without being tied to each other.
What I mean, Testing one of their own function.
What I do is as follows
chat_app_connect.spec.js
describe('Server Connecting Test', () => {
it('Visit Server page', () => {
cy.visit('https://chat.page..');
});
it('Check welcome messages', () => {
cy.contains('Live Support');
cy.contains('Hello, Stranger');
});
it('Check URL and status of circle', () => {
// URL
cy.url()
.should('include', '/hello');
// Status Circle
cy.get('circle')
.should('have.class', 'positive');
});
});
chat_connect.spec.js
import './chat_app_connect.spec.js';
describe('Chat Connecting Test', () => {
it('Type customer name', () => {
cy.get('input')
.clear()
.type('E2E Test');
});
it('Click to the submit button', () => {
cy.get('.submit-button')
.click();
});
it('Check URL and status of circle', () => {
// URL
cy.url()
.should('equal', 'https://client.dev.octopus.chat/');
// Status Circle
cy.get('circle', { timeout: 5000 })
.should('have.class', 'positive');
});
});
chatting.spec.js
import './chat_connect.spec.js';
describe('Chatting Tests', () => {
it('Type a test message then press Enter and check the message if it sent', () => {
// Type
cy.get('#chat-message')
.clear()
.type('Hey I\'m a test message{enter}');
// Check the message
cy.get('.message-list')
.should('contain', 'Hey I\'m a test message');
});
});
as you see every test is tied to each other, and that is mean when I tried to test just catting functionality its call every test and the whole tests will be tested.
I don't know if it is the right way or not.
what should I do in this case or can it be an acceptable way
I have a particular case where I launch multiple instances of an app, rather than using fixtures or test data, I simply integrate user feedback as Cypress tests from login on forwards.
In any case, I used the specPattern config in cypress.json to set the spec file run order:
{
"baseUrl": "http://localhost:5000",
"specPattern": [
"login/*.js",
"leads/new-lead.spec.js",
"leads/leads-list.spec.js",
"leads/lead-detail.spec.js",
"leads/lead-modify.spec.js",
//...
]
}
No file numbering needed :D
The easiest solution is most likely to add a prefix to all your test files, such as:
01-chat_app_connect.spec.js
02-chat_connect.spec.js
etc.
Cypress is going to take those files in alphabetical order, which you can "trick" into your wanted behavior by using a number as a prefix.
Jean Lescure's answer was a lifesaver. We needed to run tests based on priority without having a bunch of duplicated tests or symlinks. The following worked for us in our default cypress config file:
"integrationFolder":"cypress/integration",
"testFiles": [
"high_priority_specs/**/*.js",
"medium_priority_specs/**/*.js",
"low_priority_specs/**/*.js"
]
To change the level of priority we used 3 configs files that were loaded using the cypress --configFile argument. To run the higher priority tests (smoke tests only) we used the following:
"integrationFolder":"cypress/integration",
"testFiles": [
"high_priority_specs/**/*.js"
]
Cypress does not intentionally let you do this, and for good reasons:
It's generally indicative of poor test design. Tests should not depend on the state of one another. Any test should be able to be run successfully in isolation from the rest of the test suite.
You'll never be able to take advantage of cypress' built in ability to run tests in parallel since you can't guarantee one spec will be ran after another
Here is a relevant discussion about this that gets into more detail: https://github.com/cypress-io/cypress/issues/390
However, if you decide to do this anyway, you can do it by prefixing the name of the specs with a number:
01-some-spec.js
02-alphabetically-first-spec.js
03-some-other-spec.js
In addition to #Brendan answer, if you have a nested folder structure, this approach will work as well.
01-folder-name
|
- 01-some-spec.js
I have a Firebase child node with about 15,000,000 child objects with a total size of about 8 GB of data.
exampele data structure:
firebase.com/childNode/$pushKey
each $pushKey contains a small flat dictionary:
{a: 1.0, b: 2.0, c: 3.0}
I would like to delete this data as efficiently and easy as possible. How?
What i Tried:
My first try was a put request:
PUT firebase.com/childNode.json?auth=FIRE_SECRET
data-raw: null
response: {
"error": "Data requested exceeds the maximum size that can be accessed with a single request. Contact support#firebase.com for help."
}
So that didn't work, let's do a limit request:
PUT firebase.com/childNode.json?auth=FIRE_SECRET&orderBy="$key"&limitToFirst=100
data-raw: null
response: {
"error": "Querying related parameters not supported on this request type"
}
No luck so far :( What about writing a script that will get the first X number of keys and then create a patch request with each value set to null?
GET firebase.com/childNode.json?auth=FIRE_SECRET&shallow=true&orderBy="$key"&limitToLast=100
{
"error" : "Mixing 'shallow' and querying parameters is not supported"
}
It's really not going to be easy this one? I could remove the shallow requirement and get the keys, and finish the script. I was just hoping there would be a easier/more efficient way???
Another thing i tried were to create a node script that listen for childAdded and then directly tries to remove those children?
ref.authWithCustomToken(AUTH_TOKEN, function(error, authData) {
if (error) {console.log("Login Failed!", error)}
if (!error) {console.log("Login Succeeded!", authData)}
ref.child("childNode").on("child_added", function(snap) {
console.log(`found: ${snap.key()}`)
ref.child("childNode").child(snap.key()).remove( function(err) {
if (!err) {console.log(`deleted: ${snap.key()}`)}
})
})
})
This script actually hangs right now, but earlier I did receive somethings like a max stack limit warning from firebase. I know this is not a firebase problem, but I don't see any particular easy way to solve that problem.
Downloading a shallow tree, will download only the keys. So instead of asking the server to order and limit, you can download all keys.
Then you can order and limit it client-side, and send delete requests to Firebase in batches.
You can use this script for inspiration: https://gist.github.com/wilhuff/b78e7391396e09f6c614
Use firebase cli tool for this: firebase database:remove --project .
In Browser Console this is fastest way
database.ref('data').limitToFirst(10000).once('value', snap => {
var updates = {};
snap.forEach(snap => {
updates[snap.key] = null;
});
database.ref('data').update(updates);
});
Grunt will output exit codes and that's fantastic for scripts executing grunt tasks but I want the ability to handle failed grunt tasks after grunt completes them.
I was expecting to find some type of error handling function that I could set in the initConfig somewhere but I don't see anything. Likewise, even a "finally" function would work nicely.
Basically, I have an alias task that is a set of tasks that I execute and one of them temporarily changes content of a file and I write the content back to disk after everything completes. I want to still be able to at least attempt to write the content back to disk even if tasks after the mutation occurs, fail.
Something to this affect would be great.
grunt.initConfig({
onError: function (error) {
// execute my file cleanup
},
// this is essentially a "finally" function that executes once grunt
// finishes with all tasks.
onComplete: function () {
// execute my file cleanup
}
});
I am pretty sure, that there is no such feature. But it is a popular request: 1, 2.
What can be done by now? You can write a custom grunt-task, something like the following:
var errorCb = function() { callback(); }
var doneCb = function() { callback(); }
grunt.initConfig({
task_runner: {
before: ...,
beforeEach: ...,
run: ['other_task1', 'other_task2'],
after: ...,
afterEach: ...,
onError: errorCb,
onComplete: doneCb
},
other_tasks: { ... }
});
And register your task:
grunt.registerTask('task_runner', "Tasks' lifecycle", function(task, message) {
// foreach task in tasks: grunt.task.run(task)
...
// except(`grunt.util.error`)
});
As I know, there is no beatiful way to get the result of a task run. So here comes the monkey-patching. It is possible to hook these functions: grunt.fail and grunt.log.error.
Here's some inspiration: 1, 2. Also, have a look at grunt-then.
All in all, I can not say that it is an easy task. I hope someday Grunt will have events (by now: "Note that Grunt doesn't yet emit any events, but can still be useful in your own tasks.").
P.S. Have you considered Gulp for your project?
P.S.S If you are going to write your custom task, feel free to ask me for a contribution.