I run Windows10, I have a project made on Cypress and I want to log the test results both on a file AND on console: I tried just printing on a file, using in my package.json this script:
"scripts": {
"open": "./node_modules/.bin/cypress open",
"runheadless": "./node_modules/.bin/cypress run --headless --browser chrome
--spec 'cypress/integration/webpages.spec.js' > cypresstest.log"
}
And this runs smoothly; my issue is that there are more than 100 tests and it takes very long time (like 20 minutes); so I can't check if something got frozen or is working fine, because nothing is printed on console.
So I tried with
"runheadless": "./node_modules/.bin/cypress run --headless --browser chrome
--spec 'cypress/integration/webpages.spec.js' | tee cypresstest.log"
But since I'm on windows, it says
tee is not recognized as internal or external program
Is there a way, or a plugin, or something I can do to simply print both on console AND on a file log?
Cypress-terminal-report has such a feature, or you can use a custom command including cy. task instead of cy.log - for example:
cypress plugin file
module.exports = (on, config) => {
on('task', {
log (message) {
console.log(message)
return null
}
})
}
custom command:
Cypress.Commands.add("logInAndOut", (message) => {
cy.log(message)
cy.task('log', message)
});
test file
cy.logInAndOut('My log')
Edit: I found another solution - Commands. overwrite(), and I`ll list an example, but I do not recommend it, since if other people try to use the code after you - won't know the change:
Cypress.Commands.overwrite('log', (originalFn, message, args...) => {
console.log(message, args...)
// originalFn is the existing `log` command that you need to call
// and it will receive whatever you pass in here.
//
// make sure to add a return here!
return originalFn(message, args...)
})
Related
I've recently introduced commander.js to a project and use it in various scripts to parse CLI arguments. I'll give one example of where it's been used:
const { program } = require('commander');
program
.description('Import customers and accounts')
.argument('[filePath]', 'Path to JSON file containing customers and accounts', `${path.resolve(__dirname)}/data/customers.json`)
.action(filePath => {
importCustomersAndAccounts(filePath)
.catch((e) => {
console.log(e);
process.exit();
})
.finally(() => process.exit());
})
program.parse();
This script itself isn't the issue, it works fine when run from the CLI. The issue happens when I run tests that use this same script. I have the test script setup in package.json as follows:
"test": "NODE_ENV=TESTING mocha --exit --require tests/setup.js 'tests/src/**/*.spec.js' 'tests/scripts/**/*.spec.js'"
When I run the tests, I immediately get this error:
error: unknown option '--exit'
Which is being thrown by commander, not mocha. So this option getting passed to mocha when running npm run test is getting to the script itself. I've confirmed this is what's happening, because when I chained .option('--exit') after the .description() in the commander code above, it then failed with
error: unknown option '--require'
So it's reaching the next option passed to mocha and then failing on whichever option is not defined in the script. How can I prevent these options from reaching the script itself and get them to simply be parsed by mocha?
I want to get the logs written in a log file for the execution.
I am trying to create a cypress spec and I want to have log files generated for the operations performed on webpage.
There is cy.log() to log something custom but the logs are there during the run, but after it I can only see them in the video.
I want to have logs on a .log file that I can export after the cypress run is completed.
You can get the raw log records into a json file by adding code to catch the log events, and saving to a file at the end.
cypress/support/e2e.js
const logs = {}
Cypress.on('log:added', (log) => {
logs[log.id] = log
})
Cypress.on('log:changed', (log) => {
logs[log.id] = log
})
after(() => {
cy.writeFile(`logs/${Cypress.spec.name}.log.json`, logs)
})
If you use the experimentalRunAllSpecs flag to run all, the log will be written to a file logs/__all.log.json. This is how the run-all feature is working now, the specs are combined into one uber spec called __all.
You can use the cypress-log-to-file plugin to generate log files for your Cypress tests. To use this plugin, you first need to install it using npm:
npm install cypress-log-to-file
Then, in your cypress/plugins/index.js file, include the following code:
const logToFile = require('cypress-log-to-file/lib/logToFile'); module.exports = (on, config) => { logToFile(on, config); };
This will create a cypress.log file in your project's root directory that contains the logs generated during your tests' execution.
You can access this file after your tests have completed and view the logs for debugging purposes.
Checkout Cypress terminal report you can use it in your cypress.config file like below:
setupNodeEvents(on, config) {
// ...
const options = {
outputRoot: config.projectRoot + '/logs/',
outputTarget: {
'out.txt': 'txt',
'out.json': 'json',
}
};
require('cypress-terminal-report/src/installLogsPrinter')(on, options);
// ...
}
more examples on the GitHub repo readme file.
I am currently working in Cypress, I will try to semplify my question as much as possible:
I have several test files:
integration/testA.spec.js
integration/testB.spec.js
integration/testC.spec.js
I also have a config.js file in which I have an object containing the name of the test I want to run:
{
test: 'testA.spec.js'
}
what I want to do - if possible - is a main.spec.js file that, depending on the testproperty, runs the relative spec file.
I have prepared almost everything
describe('Test', () => {
before(() => {})
beforeEach(() => {})
after(() => {})
describe('Test Booking', () => {
// retrieves the `test`property and returns the string name
let testName = retrieveTestName()
console.log('testName', testName)
/** I want to do something like this */
if (testName === 'testA.spec.js') {
// launch testA.spec.js file
}
}
})
but I ignore if I can do something like the code above; do you think is possible?
Or do I have to create a script file that
checks for the namefile
uses the --spec option and launches the test
?
An option can be to create commands using the --spec file and add it under scripts in your package.json. Something like:
"scripts": {
"testA": "npx cypress run --spec "cypress/integration/testA.spec.js",
"testB": "npx cypress run --spec "cypress/integration/testB.spec.js",
"testC": "npx cypress run --spec "cypress/integration/testC.spec.js"
}
You can run directly run the above command depending on the test you want to execute.
npm run testA
I am using Testcafe (free version) with Java Script. I want to run all my test cases (resides in multiple test scripts in __test__ directory) in a single browser instance (That way 1 time log in) per browser type.
For example, 1 instance for chrome and 1 instance for safari but all tests will run before closing the browser.
If a test fails, I want the screenshot is taken and count number of the test failures. But do want to continue.
I'm doing all on Node 12 Docker image, so it is best if I don't need to install anything else.
How do I do this with Testcafe?
const createTestCafe = require('testcafe')
let testcafe = null
let runner = null
createTestCafe('localhost', 1337, 1338)
.then(tc => {
testcafe = tc
const runner = testcafe.createRunner()
return runner
.src([ '__test__/*.js' ])
.browsers([ 'chrome:headless --no-sandbox --disable-gpu', 'safari' ])
.screenshots('./reports/screenshots/', true)
.run({
selectorTimeout: 10000,
assertionTimeout: 10000,
})
})
runner
.screenshots({
path: 'reports/screenshots/',
takeOnFails: true,
})
.then(failedCount => {
console.log('Tests failed: ' + failedCount)
testcafe.close()
})
.catch(error => {
console.log("An ERROR detected:" + error)
})
This is how you install chrome on Dockerfile. Can someone tell me how to install Firefox on Dockerfile?
RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' && \
http_proxy=${http_proxy} https_proxy=${https_proxy} apt-get update && \
http_proxy=${http_proxy} https_proxy=${https_proxy} apt-get install -y --allow-unauthenticated google-chrome-stable && \
apt clean && rm -rf /var/lib/apt/lists/*
It's impossible to meet all requirements at once.
1) For example, 1 instance for chrome and 1 instance for safari but all tests will run before closing the browser.
You cannot install the Chrome and Safari web browsers on docker image. It's possible to install only Chromium and Firefox on it. See the Using TestCafe docker help topic for more information.
2) If a test fail, I want the screen shot taken and count number of test failed. But do want to continue.
TestCafe's Live mode works in the same way, but it's not available on docker.
This case you need to use Session Handling
During test execution, the Selenium WebDriver has to interact with the browser all the time to execute given commands. At the time of execution, it is also possible that, before current execution completes, someone else starts execution of another script, in the same machine and in the same type of browser.
more details
It is an awesome feature that we can use "npm programmatically," but I am running into some issues. The function "npm.load" does not seems to be firing. I am not getting any console logs that are inside of my "npm.load" or "npm.commands.install" functions.
var npm = require('npm');
// There is another promise here
.then(function(path) {
// this is working the way I intend it to
cache[requestId].package = JSON.parse(path);
// This is firing
if (cache[requestId].package.name && cache[requestId].package.version && cache[requestId].package.scripts.start) {
// console logs and an array [ 'keystone', 'async', 'underscore', 'swig', 'node-sass', 'node-sass-middleware', 'dotenv' ]
console.log(Object.keys(cache[requestId].package.dependencies));
// console logs as /Users/207004/Desktop/github/mothership/server/app/routes/tractor-beam/ms-apps/my_site
console.log(localPath);
// console logs as a [Function]
console.log(npm.load);
// *** Here is the issue! This is not firing! ***
npm.load({}, function(err) {
// no console log
console.log(npm.commands.install);
// no console log
console.log(err);
npm.commands.install(localPath, Object.keys(cache[requestId].package.dependencies), function(err, done) {
// no console log
console.log('loaded');
// no console log
console.log(err, done);
// I am assuming that this is not firing, but my code does fire the console log in the next promise
return PM2.connectAsync();
});
});
} else {
console.log('else');
}
})
// Another promise chained here. A console log inside of this promise is firing.
Any help would be appreciated. Please let me know if you have any questions.
Thanks,
It took me a few days, but I figured a lot out.
While I was working on this, it seems that the documentation for using npm programmatically was removed from npmjs.com. Not sure if it means they deprecated the module, but I decided to use "child_process" after I found that the documentation was removed.
When I stated above that "npm.load" and "npm.install" was not firing, the reason was that I had my node app running with the npm "nodemon." Every time I would run "load" or "install" nodemon would consider this a change to the directory and my app would restart. I ran into the same issue with "child_process" as well. Really dumb! I know!
With my solution provided below, it takes npm install a while to run programmatically, so plan accordingly.
Here is the solution I came up with and it's with promises:
var Promise = require('bluebird');
// This will create promise functions for all the methods in the "child_process" module.
// Created "exec.execAsync" below.
var exec = Promise.promisifyAll(require('child_process'));
// Function to make package names one long string for the command line.
var getDependencies = function(dependencies) {
var deps = '';
Object.keys(dependencies).forEach(function(el){
deps = deps + ' ' + el;
});
return deps;
};
// Promise before this reads the package.json file
.then(function(packageJson){
var deps;
var pack = JSON.parse(packageJson);
if(pack && pack.dependencies) {
deps = getDependencies(pack.dependencies);
// I used the "--prefix" flag because I wanted to install the dependencies in a different directory.
// This part takes a while. Plan your promises before and after accordingly.
// The command below console logs into this "npm install --prefix /Users/Max/Desktop/github/mothership/server/app/routes/tractor-beam/ms-apps/my_site keystone async underscore swig node-sass node-sass-middleware dotenv"
return exec.execAsync('npm install --prefix ' + localPath + deps);
}
})
// Continues to next promise
Let me know if you have any questions.