I want to log some messages while running a test. The messages are logging just fine with the statement console.log but I want to log the messages in green color so I am writing like below but all of it is coming as text rather than green color.
console.log(`%c ${process.name} completed`, 'color: green');
the output is
%c Process1 completed 'color:green'
expected output is (in green color)
Process1 completed
I suggest you use the "colors" Node module. For example:
import Colors from 'colors'
test('My test', async t => {
console.log("Process1 completed".green);
});
Related
When tests pass in Cypress it doesn't show the steps but if fails it shows all the steps and what step caused test to fail.
I want to see passing tests body/steps too.
Below image shows a passing test and a failing test. Failing test is much more informative. I want passing test to be like that too. How can I achieve this?
it('should select shipment method and type "test" into additional
notes', function () {
cy.intercept('GET',
'**/GetDetailWithAvailableCampaign*').as('basketDetails')
cy.on('uncaught:exception', (err, runnable) => { // If CheckoutJS throws an error, it will be caught here
cy.get('[data-cy="information::forward"]').click()
cy.url().should('include', '/basket/checkout/payment')
cy.get('[data-cy="shipping::shipment_type"]').first().click()
cy.get('[data-cy="shipping::shipment_type"]').should('be.checked')
cy.get('[data-cy="misc::additional_message_checkbox"]').check({force: true}).should('be.checked')
cy.get('[data-cy="misc::additional_message_textarea"]').should('be.visible').clear().type('Test')
// there is no shipping::forward
// cy.get('[data-cy="shipping::forward"]').click()
cy.get('[data-cy="information::forward"]').click()
})
})
it('should focus iframe and put a credit card', function () {
cy.wait(4000)
cy.url().should('include', '/basket/checkout/shipping')
const iframeSelector = 'iframe[data-cy="payment::iframe"]'
getIframeBody(iframeSelector).find('.btn-card-visa').click()
cy.wait(2000)
getIframeBody(iframeSelector).find('input#CardNumber').clear().type(Cypress.env('credit_card').number)
getIframeBody(iframeSelector).find('input#Expiry').clear().type(Cypress.env('credit_card').expiry)
getIframeBody(iframeSelector).find('input#HolderName').clear().type(Cypress.env('credit_card').holder_name)
getIframeBody(iframeSelector).find('input#VerificationCode').clear().type(Cypress.env('credit_card').cvv)
getIframeBody(iframeSelector).find('.btn-next').click()
}
By default, clicking on a test's name in the runner will expand and show all steps executed. In your case, it is doing this. But the issue you are running into is most likely that the uncaught:exception event you are waiting for in the first test is not occurring, and therefore no steps are executed. If you remove the cy.on('uncaught:exception'), you'll see the steps are executed.
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 installed Sublime Text 3. I installed Package Control, R-Box, SendText, SendCode, sublimeREPL, and 1337 Color Scheme. To test that REPL R is working I ran the code:
getwd()
The output was
R:/R_WD.
That's the correct location.
What I want to do is send code from one window to REPL R and have it evaluated. It originally would send code to the REPL R window and I could run the code but I wanted to be able to have it run automatically. I tried looking on forums for ideas and changed some settings. Now it will not send code to REPL R.
Here are my settings:
Preferences --> Package Settings --> R-Box --> Settings:
{
// enable auto completions
"auto_completions": true,
// show popup hints
"show_popup_hints": true,
// path to Rscript, for example
// (mac, linux): "/usr/local/bin/Rscript"
// (windows): "C:\\Program Files\\R\\R-x.y.z\\bin\\Rscript.exe"
"rscript_binary": null,
// additional paths to PATH variable
"additional_paths": []
}
User:
{
"prog": "Cmder",
}
Preferences --> Package Settings --> SendText --> Settings---> Default:
{
// Uncomment the program you want send text to:
"program": "Terminal.app",
// "program": "iTerm",
// "program": "tmux",
// "program": "screen",
"paths":
{
// It might be necessary to explicitly set path (usually /usr/bin
// or /usr/local/bin) to tmux and screen. Uncomment below and specify
// the correct path:
// "tmux": "/usr/local/bin/tmux",
// "screen": "/usr/local/bin/screen"
}
}
Preferences --> Package Settings --> SendText --> Settings---User:
{
"prog": "Cmder",
}
Preferences --> Package Settings --> SendCode--> Settings:
{
"prog": "Cmder",
}
Preferences --> Package Settings -->SublimeREPL--> Settings---Default:
{
// default_extend_env are used to augment any environment variables
// that should be visible for all subprocess repls launched within
// SublimeREPL. This is a very good place to add PATH extension
// once "PATH": "{PATH}:/home/username/mylocalinstalls/bin" or whatever
"default_extend_env": {},
// Specify whether to move repls to a different Sublime Text group (frame)
// immediately on opening. Setting this to true will simply move it to
// the 'next' group from the one that was in focus when it was opened
// (one down with row layout, one to the right with column and grid
// layout). Alternatively, you can set this to the index of the group in
// which you want all repls to be opened (index 0 being the top-left group).
// Activating this option will NOT automatically change your layout/create
// a new group if it isn't open.
"open_repl_in_group": true,
// Persistent history is stored per REPL external_id, it means that all python
// REPLS will share history. If you wish you can disable history altogether
"persistent_history_enabled": true,
// By default SublimeREPL leaves REPL view open once the underlying subprocess
// dies or closes connection. This is useful when the process dies for an unexpected
// reason as it allows you to inspect it output. If you want. Setting this
// to true will cause SublimreREPL to close view once the process died.
"view_auto_close": false,
// On POSIX system SublimeText launched from GUI does not inherit
// a proper environment. Often leading to problems with finding interpreters
// or not using the ones affected by changes in ~/.profile / *rc files
// This command is used as a workaround, it's launched before any subprocess
// repl starts and it's output is parsed as an environment
"getenv_command": ["/bin/bash", "--login", "-c", "env"],
// Some terminals output ascii color codes which are not currently supported
// enable this option to filter them out.
"filter_ascii_color_codes": true,
// Where to look for python virtualenvs
"python_virtualenv_paths": [
"~/.virtualenvs", // virtualenvwrapper
"~/.venv" // venv.bash https://github.com/wuub/venv
],
// Use arrows for history navigation instead of Alt+[P|N]/Ctrl+[P|N]
"history_arrows": true,
// standard sublime view settings that will be overwritten on each repl view
// this has to be customized as a whole dictionary
"repl_view_settings": {
"translate_tabs_to_spaces": false,
"auto_indent": false,
"smart_indent": false,
"spell_check": false,
"indent_subsequent_lines": false,
"detect_indentation": false,
"auto_complete": true,
"line_numbers": false,
"gutter": false
},
// this settings exposes additional variables in repl config files, especially
// those related to sublime projects that are not available through standard API
// WARNING: this will switch your build system back to Automatic each time a REPL
// is started so beware!
"use_build_system_hack": false,
// IP address used to setup autocomplete server in sublimerepl.
// changing this is usefull when you want to exclude one address
// from proxychains/tsocks routing
"autocomplete_server_ip": "127.0.0.1",
// Mapping is used, when external_id of REPL does not match
// source.[xxx] scope of syntax definition used to highlight
// files from which text is being transfered. For example octave
// repls use source.matlab syntax files and w/o this mapping text transfer
// will not work
"external_id_mapping": {
"octave": "matlab"
},
// If set to true, SublimeREPL will try to append evaluated code to repl
// output before evaluation (e.g. Ctrl+, f)
"show_transferred_text": true,
// If set to true repl view (tab) that receives text for evaluation will
// be brought to front after text transfer. Note: This will not fire if repl
view
// is in the same tab group as the view from which the code is sent.
"focus_view_on_transfer": true
}
Preferences --> Package Settings -->SublimeREPL-->Settings--- User:
{
"default_extend_env": {"PATH": "{PATH};R:\\R_WD\\R\\R-3.4.2\\bin\\x64"},
"show_transferred_text": true
}
I noticed that the comments said to uncomment or add code but I can't seem to edit the code in those locations.
Any help is appreciated. If there is any clarification needed, I'm happy to provide more info.
This is how I changed the code to get it to work:
I changed "Preferences --> Package Settings --> SendText --> Settings---User:" from:
{
"prog": "Cmder",
}
to:
{"r" : {
"prog": "cmder",
}
{ "rscript_binary" : "R:\\R_WD\\R\\R-3.4.2\\bin\\Rscript.exe"
}
}
All the other user settings code that was:
{
"prog": "Cmder",
}
I changed to:
{"r" : {
"prog": "cmder",
}
}
I can now send the code to be automatically evaluated with the default option.
I have a log file (zope/plone event.log) which using custom string (e.g "-----") as divider between events, how grok pattern for parsing this log file to logstash should be?
This is an example how the log look like:
------
2014-07-21T12:13:30 INFO ZServer HTTP server started at Mon Jul 21 12:13:30 2014
Hostname: localhost
Port: 8401
------
2014-07-21T12:13:44 WARNING SecurityInfo Conflicting security declarations for "setText"
------
2014-07-21T12:13:44 WARNING SecurityInfo Class "ATTopic" had conflicting security declarations
------
2014-07-21T12:13:47 INFO DocFinderTab Applied patch version 1.0.5.
You should start with the multiline codec or filter to create a single event for processing.
EDIT:
The doc gives this example:
filter {
multiline {
pattern => "pattern, a regexp"
negate => boolean
what => "previous" or "next"
}
}
And describes what 'negate' and 'what' do. Hopefully 'pattern' make sense.
So, how about "every line that doesn't start with a date belongs with the prior line"? That might be something like this:
filter {
multiline {
negate => 'true'
pattern => "^%{TIMESTAMP_ISO8601} "
what => 'previous'
}
}
You'd be left with the "----" at the end of each line. Since you don't need them as delimiters, you can get rid of them (before the multiline filter stanza):
if message =~ /^-+$/ {
drop{}
}
I have this site: http://embed.plnkr.co/Bs5iDqtXSSnvye2ORI6k/preview
Code:
var app = angular.module('plunker', []);
var a = new Array(1000);
for (var i = 0; i< 1000; i++) {
a[i] = 'Name' + i;
}
app.controller('MainCtrl', function($scope, $interval) {
$scope.names = a;
$scope.start = function () {
$interval(function () {
$scope.names.pop();
}, 50);
}
});
And the following spec:
'use strict';
describe('Name list', function () {
it('should get the text of the last name', function () {
browser.driver.get('http://embed.plnkr.co/Bs5iDqtXSSnvye2ORI6k/preview');
browser.switchTo().frame(browser.driver.findElement(protractor.By.tagName('iframe')));
element(by.buttonText('start')).click();
expect(element.all(by.tagName('span)).last().getText()).toBe('Name999');
});
});
And this config:
'use strict';
// An example configuration file.
exports.config = {
baseUrl: 'http://localhost:3000',
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['stale.spec.js']
};
And when I run Protractor I get the following error:
StaleElementReferenceError: stale element reference: element is not
attached to the page document (Session info: chrome=43.0.2357.81)
(Driver info: chromedriver=2.15.322455
(ae8db840dac8d0c453355d3d922c91adfb61df8f),platform=Mac OS X 10.10.3
x86_64) (WARNING: The server did not provide any stacktrace
information) Command duration or timeout: 9 milliseconds For
documentation on this error, please visit:
http://seleniumhq.org/exceptions/stale_element_reference.html Build
info: version: '2.45.0', revision: '5017cb8', time: '2015-02-26
23:59:50' System info: host: 'ITs-MacBook-Pro.local', ip:
'129.192.20.150', os.name: 'Mac OS X', os.arch: 'x86_64', os.version:
'10.10.3', java.version: '1.8.0_31' Driver info:
org.openqa.selenium.chrome.ChromeDriver Capabilities
[{applicationCacheEnabled=false, rotatable=false,
mobileEmulationEnabled=false,
chrome={userDataDir=/var/folders/rr/63848xd90yscgwpkfn8srbyh0000gq/T/.org.chromium.Chromium.rarNyX},
takesHeapSnapshot=true, databaseEnabled=false, handlesAlerts=true,
version=43.0.2357.81, platform=MAC, browserConnectionEnabled=false,
nativeEvents=true, acceptSslCerts=true, locationContextEnabled=true,
webStorageEnabled=true, browserName=chrome, takesScreenshot=true,
javascriptEnabled=true, cssSelectorsEnabled=true}] Session ID:
235ec977a69d98c7f5b75a329e8111b2
This means that the element I try to interact with (getting the text of the element), isn't attached to the DOM anymore. This example is really my spec simplyfied. What really happens in my real spec is I try to get the text of the last element of a list of elements (generated by ng-repeat). What also happens is that the model updates, by removing the last element of the array representing the list of element. This example above is just something to reproduce the error (every time).
If I comment out this line: element(by.buttonText('start')).click(); the spec is successful.
I struggled a lot with this and tried to figure out why this would happen. I first thought that the element finder which points to the last element of the list was created long before the interaction was done, so there was no surprise to me that the element could be detached from the DOM in that period of time between the creation of the element finder and the interaction.
What I've later found out is that the element is found just before the interaction is done, every time you interact with something. So pointing to the last element should actually point to the last element of the time interacting with the element.
Using browser.pause() I was able to see what WebDriver really does, and this is two tasks where in between the error is thrown:
(pending) Task::414<WebDriver.findElements(By.tagName("span"))>
| | | | | | Task: WebDriver.findElements(By.tagName("span"))
| | | | | | at Array.forEach (native)
Here in between, the DOM is updated according to the model, and the last element of the list is detached.
(pending) Task::1170<WebElement.getText()>
| | | | | | Task: WebElement.getText()
| | | | | | at Array.forEach (native)
The DOM is updated in this small hole of execution. Currently the model updates every 50 ms, and this is sure to throw a Stale Element Reference error. But if I increase the interval to, say 1000 ms, then the chance to get the error is much less. So it depends on how fast your computer runs if you get this error.
The fix is up to you, but with this information it should be a bit clearer what to do, I hope.
The browser is running asynchronously from your protractor tests. This example really highlights that nicely (its a problem for many protractor tests, but not usually so obvious). This is compounded by what looks like a single line:
expect(element.all(by.tagName('span')).last().getText()).toBe('Name999');
actually requires several round-trips to the browser (there are a lot of promises being returned and resolved: element.all, last, getText). For most web pages that are "passive" once they've stabilized, this isn't a problem, but for any web page that dynamically changes without user inputs, testing with protractor can be painful.
To make a lookup and test "atomic" in the browser, thus side-steping this issue, you can define a function to run in the browser (my CSS DOM-fu is weak, so hopefully someone can tweak this to make it less terrible):
expect(browser.executeScript(function() {
var spans = document.getElementsByTagName('span');
var lastSpan = spans[spans.length - 1]; // XXX handle empty spans
return lastSpan.innerText;
}).toBe('Name999');
Beware that the "function" is serialized and executed on the browser, so no variables from an enclosing scope will work. Also, this approach loses any browser-compatibility magic hiding in protractor or webdriver (e.g., I wouldn't be surprised if getText() wasn't simply a innerText accessor).
Also, note that you still have a race condition. Between the 'click' to get things started and this code to actually inspect the DOM, it may or may not have been mutated (and "Name999" might be gone).