Following this discussion I attempted to debug a mocha test script via the following:
mocha --inspect-brk ./tests/foo.test.js
This does indeed present an inspector URL that I can bind to in Chrome, but the "sources" are populated only with the source of mocha itself, not my code - is there something I need to change to get the inspector to bring up my code and not mocha's?
(I did see a similar question but I'm hoping for an answer that doesn't involve bringing in another dependency like node-inspector.)
Add debugger to one of your tests. When you resume in dev tools, execution will pause in your test code and you can browse your files.
it('should replace a template string', function(){
debugger
expect( Helper.templateString('{{a}}', {a:2}) ).to.equal( '2' )
})
You can also step over _mocha until it loads the files, which is around line 460 in v5.0.4, labeled requires:
// requires
requires.forEach(mod => {
require(mod);
});
After this you can browse your files and set break points. Dev tools will remember the break points for the next run.
Related
I have a Cypress project where I use the Cypress session API to maintain a session throughout features.
Now I try switching from the deprecated Klaveness Cypress Cucumber Preprocessor to the replacement, Badeball's Cypress Cucumber Preprocessor. But I am running into an issue; the beforeEach() step where my authentication takes place gets repeated several times before the tests start. Eventually, Cypress "snaps out of it" and starts running the actual tests - but obviously this is very resource and time intensive, something is going wrong.
My setup:
Dependencies:
"cypress": "^9.6.1",
"#badeball/cypress-cucumber-preprocessor": "^9.1.3",
index.ts:
beforeEach(() => {
let isAuthInitialized = false;
function spyOnAuthInitialized(window: Window) {
window.addEventListener('react:authIsInitialized', () => {
isAuthInitialized = true;
});
}
login();
cy.visit('/', { onBeforeLoad: spyOnAuthInitialized });
cy.waitUntil(() => isAuthInitialized, { timeout: 30000 });
});
login() function:
export function login() {
cy.session('auth', () => {
cy.authenticate();
});
}
As far as I can see, I follow the docs for cy.session almost literally.
My authenticate command has only application specific steps, it does include a cy.visit('/') - after which my application is redirected to a login service (different domain) and then continues.
The problem
cy.session works OK, it creates a session on the first try - then each subsequent time it logs a succesful restore of a valid session. But this happens a number of times, it seems to get stuck in a loop.
Screenshot:
It looks to me like cy.visit() is somehow triggering the beforeEach() again. Perhaps clearing some session data (localstorage?) that causes my authentication redirect to happen again - or somehow makes Cypress think the test starts fresh. But of course beforeEach() should only happen once per feature.
I am looking at a diff of my code changes, and the only difference except the preprocessor change is:
my .cypress-cucumber-preprocessorrc.json (which I set up according to the docs
typing changes, this preprocessor is stricter about typings
plugins/index.ts file, also set up according to the docs
Am I looking at a bug in the preprocessor? Did I make a mistake? Or something else?
There are two aspects of Cypress + Cucumber with preprocessor that make this potentially confusing
Cypress >10 "Run all specs" behaviour
As demonstrated in Gleb Bahmutov PhD's great blog post, if you don't configure Cypress to do otherwise, running all specs runs each hook before each test. His proposed solution is to not use the "run all specs" button, which I find excessive - because there are ways around this; see below for a working solution with the Cucumber preprocessor.
Note: as of Cypress 10, "run all specs" is no longer supported (for reasons related to this unclarity).
Cucumber preprocessor config
The Cypress Cucumber preprocessor recommends to not use the config option nonGlobalStepDefinitions, but instead configure specific paths like (source):
"stepDefinitions": [
"cypress/integration/[filepath]/**/*.{js,ts}",
"cypress/integration/[filepath].{js,ts}",
"cypress/support/step_definitions/**/*.{js,ts}",
]
}
What it doesn't explicitly state though, is that the file which includes your hooks (in my case index.ts) should be excluded from these paths if you don't want them to run for each test! I could see how one might think this is obvious, but it's easy to accidentally include your hooks' file in this filepath config.
TLDR: If I exclude my index.ts file which includes my hooks from my stepDefinitions config, I can use "run all specs" as intended - with beforeEach() running only once before each test.
I am using cypress with cucumber-js and i need to define my own data type. I did exactly same things like is described in https://github.com/TheBrainFamily/cypress-cucumber-preprocessor#custom-parameter-type-resolves.
That means:
cypress > support > step_definitions > customParameterTypes.js
I wrote:
const blogType = ["sport", "gaming"]
defineParameterType({
name: "blogType",
regexp: new RegExp(blogType.join("|"))
})
and in my BDD .feature file i have:
Given I have empty blog
And Blog has default structure for sport
and in my cypress file:
Given(' Blog has default structure for {blogType}', blogType => {...})
When i start my test i get:
The following error originated from your test code, not from Cypress.
> Undefined parameter type {blogType}
When Cypress detects uncaught errors originating from your test code it will automatically fail the current test.
Cypress could not associate this error to any specific test.
For some reasons, I've had problems using defineParameterType() in the past, and am now using regexp in all my BDD projects.
In your .js file:
Given(/^Blog has default structure for (sport|gaming)$/, blogType => {...});
Using the above, you won't need customParameterTypes.js and your .feature file stays the same.
I'm just beginning to use Jest in my nodejs project. I have several test and all pass, but the last test I just coded is passing but is blocked in two places by Jest with code like this:
/* istanbul ignore next */
cov_19rdmie87d().s[43]++;
debugger;
/* istanbul ignore next */
cov_19rdmie87d().s[53]++;
this debugger;
I have to hit f5 to continue twice while running my tests. How can I remove these debugging statements?
Solution:
Remove debugger statements from your code and any kind of breakpoints from your inspect sources.
Some more Wiki on Debugging in JS
Debugger : If you place a debugger; line in your code, Chrome will automatically stop there when executing. You can even wrap it in conditionals, so it only runs when you need it.
Type debug(item.myFunc) in the console and the script will stop in debug mode when it gets a function call to item.myFunc
When you need to debug JavaScript, Chrome lets you pause when a DOM element changes. You can even monitor its attributes. In Chrome Inspector, right-click on the element and pick a break on setting to use.
For more information, check out this article by raygun on debugging in javascript.
I like letting mocha -w run in a terminal while I work on test so I get immediate feedback, but I can't always tell from a glance if it's changed or not when the status doesn't change - did it run, or did it get stuck (it's happened)?
I'd like to have a way to append a timestamp to the end of each test run, but ideally only when run in 'watch' mode - if I'm running it manually, of course I know if it ran or not.
For now, I'm appending an asynchronous console log to the last test that runs:
it('description', function () {
// real test parts.should.test.things();
// Trick - schedule the time to be printed to the log - so I can see when it was run last
setTimeout(() => console.log(new Date().toDateString() + " # " + new Date().toTimeString()), 5);
});
Obviously this is ugly and bad for several reasons:
It's manually added to the last test - have to know which that is
It is added every time that test is run, but never others - so if I run a different file or test -> no log; if I run only that test manually -> log
It's just kind of an affront to the purpose of the tests - subverting it to serve my will
I have seen some references to mocha adding a global.it object with the command line args, which could be searched for the '-w' flag, but that is even uglier, and still doesn't solve most of the problems.
Is there some other mocha add-in module which provides this? Or perhaps I've overlooked something in the options? Or perhaps I really shouldn't need this and I'm doing it all wrong to begin with?
Mocha supports root level hooks. If you place an after hook (for example) outside any describe block, it should run at the end of all tests. It won't run only in watch mode, of course, but should otherwise be fit for purpose.
I have a codebase where I have quite a number of
debugger;
statements. Sometimes I debug, and I actually just want to skip all of the debugger; statements and continue only to the manually set breakpoints that I have chosen for the debugging session, is there some setting by chance with Node.js to do that?
In other words, I would like to consider the debugger; statements to be long-term placeholders, but for certain debugging sessions I would like to ignore those long-term placeholders.
That can be done with the chrome devtools.
You can do:
node --inspect --debug-brk index.js
that will generate something like this:
chrome-devtools://devtools/remote/serve_file/#60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=localhost:9229/9c2e4f37-4c3a-4477-b8da-2399c5d9819e
Just copy and paste that on chrome.
There is an option to disable/enable all the break points, and chrome will remember all the breakpoints that you set previously.
Please check: --inspect for more info.
A trick I've used in the past is to just use babel to strip out debugger statements:
See:
https://www.npmjs.com/package/babel-plugin-remove-debugger
Quick and dirty way (its for debug so, its fine really) is to stick something like the following script in scripts/debugger.js
require.extensions['.js'] = function(module, filename) {
var content = fs.readFileSync(filename, 'utf8').replace(/debugger/g, [
'(function() {',
' if (__debugger) {',
' debugger;',
' }',
'})',
].join('\n'));
module._compile(content, filename);
};
then start node with node -r ./scripts/debugger
Using a global variable here so that it can be enabled/disabled from the debugger repl or chrome's repl if debugging with --inspect.
Technically require.extensions is deprecated, but it's not going to be removed and it works as intended here.