Cypress + Cucumber - same steps definition - cypress-cucumber-preprocessor

Let's say I have Feature1.feature and Feature2.feature files. In first I have steps:
Scenario: Test scenario1
Given I Open the app
When I Click on Tab1
And in the second file I have:
Scenario: Test scenario2
Given I Open the app
When I Click on Tab2
Under the step_definitions folder in step1.js file:
Given("I open the app", () => {
cy.visit("/home");
});
When("I Click on Tab1", () => {
cy.get('[title="Tab1"]'.click();
});
Under the step_definitions folder we have multiple js files (separated by each testing case). So for the 2nd scenario, in step2.js do I need to define the Open app step again? :
Given("I open the app", () => {
cy.visit("/home");
});
Or it looks globally in all files under the steps_definition? So then I just need to start with:
When("I Click on Tab2", () => {
cy.get('[title="Tab2"]'.click();
});
But what if multiple users are working on test cases and they accidentally define the same steps in different files, e.g.
In one file
Given("I open the app", () => {
cy.visit("/home");
});
In other file
Given("I open the app", () => {
cy.visit("/news");
});
As I read, each scenario should be independent. But if there are same steps for each scenario? We need to define them only once just in one file. But if someone else is working on that file, it may break my scenario.

If there are two steps for multiple scenarios you should use common steps:
Reusable step definitions
We also have a way to create reusable step definitions. Put them in cypress/integration/common/
Example: cypress/integration/common/i_see_string_in_the_title.js
import { Then } from "cypress-cucumber-preprocessor/steps";
Then(`I see {string} in the title`, (title) => {
cy.title().should('include', title)
})
taken from https://www.npmjs.com/package/cypress-cucumber-preprocessor

Related

is there a way to check if the PWA was launched through a file or not?

I'm using the file handle API to give my web app the optional capability to launch through double-clicking files in the file explorer.
Writing the code below, I expected if (!("files" in LaunchParams.prototype)) to check if a file was used to launch the app, but apparently, it checks if the feature is supported. OK, that makes sense.
After that, I thought the setConsumer callback would be called in any launch scenario, and files.length would be zero if the app was launched in other ways (like by typing the URL in the browser). But on those use cases, the callback was not called at all, and my init logic was never executed.
if (!("launchQueue" in window)) return textRecord.open('a welcome text');
if (!("files" in LaunchParams.prototype)) return textRecord.open('a welcome text');
launchQueue.setConsumer((launchParams) => {
if (launchParams.files.length <= 0) return textRecord.open('a welcome text');
const fileHandle = launchParams.files[0];
textRecord.open(fileHandle);
});
I've also followed the Launch Handler API article instructions and enabled the experimental API.
The new code confirms that "targetURL" in LaunchParams.prototype is true, but the setConsumer callback is not executed if the user accesses the web app through a standard browser tab.
function updateIfLaunchedByFile(textRecord) {
if (!("launchQueue" in window)) return;
if (!("files" in LaunchParams.prototype)) return;
console.log({
'"targetURL" in LaunchParams': "targetURL" in LaunchParams.prototype,
});
// this is always undefined
console.log({ "LaunchParams.targetURL": LaunchParams.targetURL });
// setConsumer does not trigger if the app is not launched by file, so it is not a good place to branch what to do in every launch situation
launchQueue.setConsumer((launchParams) => {
// this never run in a normal tab
console.log({ setConsumer: launchParams });
if (launchParams.files.length <= 0) return;
const fileHandle = launchParams.files[0];
textRecord.open(fileHandle);
});
}
This is the result...
Is there a universal way to check if the web app was launched through a file?
Check out the Launch Handler origin trial. It lets you determine the launch behavior exactly and lets your app detect how the launch happened. This API works well together with the File Handling API that you already use. You could, for example, check the LaunchParams.targetURL to see how the app was launched. Your feedback is very welcome.
Since I was not able to guarantee that the setConsumer callback was called in every situation (especially when the app is launched in a regular browser tab), I hacked it through setTimeout:
function wasFileLaunched() {
if (!("launchQueue" in window)) return;
if (!("files" in LaunchParams.prototype)) return;
return new Promise((resolve) => {
let invoked = false;
// setConsumer does not triggers if the app is not launched by file, so it is not a good place to branch what to do in every launch situation
launchQueue.setConsumer((launchParams) => {
invoked = true;
if (launchParams.files.length <= 0) return resolve();
const fileHandle = launchParams.files[0];
resolve(fileHandle);
});
setTimeout(() => {
console.log({ "setTimeout invoked =": invoked });
if (!invoked) resolve();
}, 10);
});
}

How to get the name of selected files in source control via VSCode extension API?

I can manage to get one file name of source control with following code. The file name is from the line 'await vscode.commands.executeCommand('copyFilePath');' I can get the file name by reading the clipboard text. But when I select multiple files, still the first file name is available. Is it possible to get all files' name?
let copySelectedFileName = vscode.commands.registerCommand('folder-operations.copySelectedFileName', async (folder) => {
let newUri = folder; // folder will be undefined when triggered by keybinding
console.log('folder'+folder);
if (!folder) { // so triggered by a keybinding
await vscode.commands.executeCommand('copyFilePath');
}
console.log(newUri);
});
I try another way: add one command to SCM as below shown.
I use parameter in command to retrieve the selected files' name. But the size of the array is 1 even if I choose more than 2 files.
let copySelectedFileNameSCM = vscode.commands.registerCommand('testSource.copySelectedFileNameSCM', async (...file) => {
console.log('file:'+file);
});
Add your command to this context menu in your package.json:
"contributes": {
"menus": {
"scm/resourceState/context": [
{
"command": "testSource.copySelectedFileNameSCM"
}
]
}
}
It looks like you were adding it to the wrong menu. That may be the only menu that will return selected files.
Then in your command:
let copySelectedFileNameSCM = vscode.commands.registerCommand('testSource.copySelectedFileNameSCM', async (...file) => {
console.log('file:'+file);
});
file will be an array of all selected items in the scm view when you trigger a context menu on one or more selected files.

How to get path of selected directory into renderer process

I want to store in variable the path of local directory selected using dialog.showOpenDialog.
I tried every tutorial and stack answer without any luck.
Best part is that even the electron-api-demos solution isn't working (I am using one here)
So, dialog opens, I can select a folder or a file - but nothing is send back to renderer process.
Here I am testing this with opening files but also no results.
I am using jquery btw and elcetron v 12.
Here is my code:
Renderer process:
$('.js_select_folder').on('click', (e) =>{
ipcRenderer.send('open-folder')
e.preventDefault();
})
ipcRenderer.on('selected-folder', (event, path) => {
console.log('wtf',path)
$('#info').text('Result :'+path)
})
Main process:
ipcMain.on('open-folder', (event) => {
dialog.showOpenDialog({ properties:['openFile']}, (files) => {
if(files){
console.log(files)
event.reply('selected-folder', files)
}
})
})
No trace of console.log(files) anywhere.
Any ideas what I am doing wrong?
I figured it out:
renderer process:
$('.js_test').on('click', (e)=>{
e.preventDefault();
ipcRenderer.send('open-folder')
})
ipcRenderer.on('sel-dir', (event, path) => {
const message = `This app is located at: ${path}`
$('#info').text(message)
})
main process:
ipcMain.on('open-folder', (event, arg) => {
dialog.showOpenDialog({properties: ['openDirectory']}).then(result=>{
event.sender.send('sel-dir', result.filePaths)
})
})
So it is actually super simple as you can see but took me two days to figure it out.
The result is that I get the path (or any data) back to renderer after choosing dir or file.
Regards, Mac.

cucumber stepdefinition file is not recognized by the protractor cucumber config file

unable to execute the steps in the step definition file
i tried the solutions present in the google but none of them are answer my questions.
my Config file
//seleniumAddress: 'http://localhost:4444/wd/hub',
directConnect: true,
//specs: ['/Users/bharaniravisankar/Desktop/PRO/SPECS/TEST.JS'],
framework: 'custom',
// path relative to the current config file
frameworkPath: require.resolve('protractor-cucumber-framework'),
capabilities: {
'browserName': 'chrome'
},
specs: [
'/Users/bharaniravisankar/Desktop/PRO/Feature/test.feature'
],
cucumberOpts: {
require: '/Users/bharaniravisankar/Desktop/PRO/Feature/Step Definition/login.js',
//tags: false,
//format: 'pretty',
profile: false,
'no-source': true
}
};
my console log
? Given User navigate to Home Page
Undefined. Implement with the following snippet:
Given('User navigate to Home Page', function () {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
? When User enter email and other details
Undefined. Implement with the following snippet:
When('User enter email and other details', function () {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
? And click on Submit button
Undefined. Implement with the following snippet:
When('click on Submit button', function () {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
? Then Login is created sucessfully
Undefined. Implement with the following snippet:
Then('Login is created sucessfully', function () {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
✔ After # CONG.js/node_modules/protractor-cucumber-framework/lib/resultsCapturer.js:26
1 scenario (1 undefined)
4 steps (4 undefined)
Stepdefinition file
var { Given, When, Then } = require("cucumber");
module.exports = function () {
this.Given(/^User navigate to Home Page$/, async function () {
// this.When('User enter email and other details', function () {
//launch AWS portal
browser.get('https://portal.aws.amazon.com/billing/signup#/start');
//Maximize the browser window
browser.driver.manage().window().maximize();
//Check the title of the Webpage
expect(await browser.getTitle()).toEqual('AWS Console - Signup');
});
this.When(/^User enter email and other details$/, function () {
// this.When('User enter email and other details', function () {
element(by.model('credentials.email')).sendKeys('bharaniravi36#gmail.com')
element(by.model('credentials.password')).sendKeys('Feb%1992');
element(by.model('credentials.rePassword')).sendKeys('Feb%1992');
element(by.model('credentials.fullName')).sendKeys('bharaniravi85');
});
//this.When('click on Submit button', function () {
this.When(/^click on Submit button$/, function () {
element(by.xpath("(//input[#class='a-button-input'])[1]")).click();
});
this.Then(/^Login is created sucessfully$/, function () {
expect(browser.getTitle()).toEqual('AWS Console - Signup');
element(by.id('company')).sendKeys('POLI');
//click on country drop down
element(by.model("address.countryCode")).click();
element(by.xpath("//option[#label='American Samoa']")).click();
// add sleep to give a time for te options to reveal
browser.sleep(3000)
});
};
in my research i didnt miss anything in my setup and every thing is setup in my system and required dependencies are downloaded.
First of all try creating the step definition folder outside the feature folder to keep separation of features and step definitions and folder name should be without spaces like 'stepdefinition'.
Secondly, make sure all the feature steps should be implemented in the step definition file and the text of each step should be the same as mentioned in the features.
Try using this and let me know, if it works for you.

Implementing a "Save As" using the vscode API

I've been trying to figure out the best way to implement a "Save As" using the vscode extension API.
So far, here's the best I've got:
// First turn the path we were given into an absolute path
// Relative paths are interpreted as relative to the original file
const newFileAbsolutePath = path.isAbsolute(saveFileDetails.newPath) ?
saveFileDetails.newPath :
path.resolve(path.dirname(saveFileDetails.filePath), saveFileDetails.newPath);
// Create an "untitled-scheme" path so that VSCode will let us create a new file with a given path
const newFileUri = vscode.Uri.parse("untitled:" + newFileAbsolutePath);
// Now we need to copy the content of the current file,
// then create a new file at the given path, insert the content,
// save it and open the document
return vscode.workspace.openTextDocument(saveFileDetails.filePath)
.then((oldDoc) => {
return vscode.workspace.openTextDocument(newFileUri)
.then((newDoc) => {
return vscode.window.showTextDocument(newDoc, 1, false)
.then((editor) => {
return editor.edit((editBuilder) => {
editBuilder.insert(new vscode.Position(0, 0), oldDoc.getText());
})
.then(() => {
return newDoc.save()
.then(() => EditorOperationResponse.Completed);
});
});
});
});
We open the old doc, then open a new doc (which is an untitled document), then insert the old doc's text into the new doc and then save the new doc.
The new doc then closes (for some reason).
Anyone have any advice?
It seems like this is a known issue and caused by the use of the untitled:// scheme:
TextDocument.save() closes untitled documents (#29156)
For now, you could work around it by just reopening the file again since you know the final URI (unlike in the case of the person who reported the issue).
newDoc.save().then((completed) => {
const finalUri = vscode.Uri.file(newFileAbsolutePath);
vscode.workspace.openTextDocument(finalUri).then((doc) => {
vscode.window.showTextDocument(doc, {preview: false});
})
});
Unfortunatenly this does lead to a noticable "flicker"-effect. To avoid this, I'd suggest to simply bypass the VSCode API and use fs for file IO, and only use vscode for showing the file at the end. This also simplifies the code quite a bit:
import * as fs from 'fs';
function runCommand() {
// obtain newFileAbsolutePath / oldFileAbsolutePath
var oldDocText = fs.readFileSync(oldFileAbsolutePath);
fs.writeFileSync(newFileAbsolutePath, oldDocText);
const finalUri = vscode.Uri.file(newFileAbsolutePath);
vscode.workspace.openTextDocument(finalUri).then((doc) => {
vscode.window.showTextDocument(doc, {preview: false});
});
}