I am having an e2e testing pack with protractor-cucumber-framework and Chai for asserting.
I have a Feature file with a data table as below.
Scenario: Menu Validation
Given I am on the home page
When I do Hover over the menu item I should have the menu dropdown
|menu1 |
|menu2 |
|menu3 |
I have the step definition as below.
When(/^I do Hover over the menu item I should have the menu dropdown/, (dataTable) => {
let rootMenu : Array<string> = Array.from( dataTable.rawTable )
rootMenu.forEach((ele) => {
console.log(ele[0]);
element(by.id(ele[0])).isPresent().then(function(present) {
expect(present).to.equal(true);
});
});
});
Even if the menu element ID is not present this test step never fail, I checked further the expect(present).to.equal(true); never get executed. I am not sure what I am missing.
can you try this instead
When(/^I do Hover over the menu item I should have the menu dropdown/, async (dataTable) => {
let rootMenu : Array<string> = Array.from( dataTable.rawTable )
for (let i; i < rootMenu.length; i++) {
let ele = = rootMenu[i];
console.log(ele[0]);
expect(await element(by.id(ele[0])).isPresent()).to.equal(true);
}
})
Related
I am planning to add multiple options to the status bar. Is it possible?
Like, If we click on the language type of a file we see multiple options in the same way.
how to create it?
Thanks
Use vscode.window.createStatusBarItem to place an item on the status bar. When the item is clicked, it runs a command, that itself runs vscode.window.showQuickPick to prompt the user to select from a list of items.
export function activate(context: vscode.ExtensionContext)
{
createStatusBarItem(context) ;
}
function createStatusBarItem(context: vscode.ExtensionContext)
{
// register a command that is invoked when the status bar
// item is clicked.
const myCommandId = 'myExtension.statusBarClick';
context.subscriptions.push(vscode.commands.registerCommand(myCommandId, async () =>
{
const pageType = await vscode.window.showQuickPick(
['shell', 'fetch rows, list in table'],
{ placeHolder: 'select type of web page to make' });
}));
// create a new status bar item that we can now manage
const item = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
item.command = myCommandId;
context.subscriptions.push(item);
item.text = `my command`;
item.tooltip = `status bar item tooltip`;
item.show();
}
I have an extension that grabs the open file's text and alters it. Once the text is altered, how do I put it back into the file that is displayed in VSCode?
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
console.log('Congratulations, your extension "myExtension" is now active!');
console.log(process.versions);
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
let disposable = vscode.commands.registerCommand('extension.myExtension', () => {
// The code you place here will be executed every time your command is executed
let activeEditor = vscode.window.activeTextEditor;
if (!activeEditor) {
return;
}
let text = activeEditor.document.getText();
getAsyncApi(text).then((textToInsertIntoDoc) => {
let finaldoc = insertTextIntoDoc(text, textToInsertIntoDoc);
// not what I want - just used to see new text
vscode.window.showInformationMessage(textToInsertIntoDoc);
});
});
context.subscriptions.push(disposable);
}
The API you can use here is TextEditor.edit, whose definition is
edit(callback: (editBuilder: TextEditorEdit) => void, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean>;
It asks for a callback as the first parameter and in the callback, you can make edits to the document by visiting editBuilder.
I put a sample extension in https://github.com/Microsoft/vscode-extension-samples/tree/master/document-editing-sample which reverses the content in current selection, which is basically a simple use TextEditor.edit.
This is a revision of the main function in Rebornix's extension sample (included with the set of Microsoft extension samples) that handles the selection issues you raised. It reverses the content of the selection(s) (leaving the selections) or if a selection is empty it will reverse the word under the cursor at that selection without leaving anything selected. It often makes sense to leave a selection, but you can add code to remove selection.
let disposable = vscode.commands.registerCommand('extension.reverseWord', function () {
// Get the active text editor
const editor = vscode.window.activeTextEditor;
if (editor) {
const document = editor.document;
editor.edit(editBuilder => {
editor.selections.forEach(sel => {
const range = sel.isEmpty ? document.getWordRangeAtPosition(sel.start) || sel : sel;
let word = document.getText(range);
let reversed = word.split('').reverse().join('');
editBuilder.replace(range, reversed);
})
}) // apply the (accumulated) replacement(s) (if multiple cursors/selections)
}
});
Admittedly, while I could remove a single selection by setting .selection to a new empty selection that doesn't seem to work with .selections[i]. But you can make multiple changes without having selections in the first place.
What you don't want to do is make a selection through code just to alter text through code. Users make selections, you don't (unless the end purpose of the function is to make a selection).
I came to this question looking for a way to apply a textEdit[] array (which is normally returned by a provideDocumentRangeFormattingEdits callback function). If you build changes in the array you can apply them to your document in your own function:
const { activeTextEditor } = vscode.window;
if (activeTextEditor) {
const { document } = activeTextEditor;
if (document) {
/*
build your textEdits similarly to the above with insert, delete, replace
but not within an editBuilder arrow function
const textEdits: vscode.TextEdit[] = [];
textEdits.push(vscode.TextEdit.replace(...));
textEdits.push(vscode.TextEdit.insert(...));
*/
const workEdits = new vscode.WorkspaceEdit();
workEdits.set(document.uri, textEdits); // give the edits
vscode.workspace.applyEdit(workEdits); // apply the edits
}
}
So that's another way to apply edits to a document. Even though I got the editBuilder sample to work correctly without selecting text, I have had problems with selections in other cases. WorkspaceEdit doesn't select the changes.
Here is the code snippet that will solve your issue :
activeEditor.edit((selectedText) => {
selectedText.replace(activeEditor.selection, newText);
})
Due to the issues I commented about in the above answer, I ended up writing a quick function that does multi-cursor friendly insert, and if the selection was empty, then it does not leave the inserted text selected afterwards (i.e. it has the same intuitive behavior as if you had pressed CTRL + V, or typed text on the keyboard, etc.)
Invoking it is simple:
// x is the cursor index, it can be safely ignored if you don't need it.
InsertText(x => 'Hello World');
Implementation:
function InsertText(getText: (i:number) => string, i: number = 0, wasEmpty: boolean = false) {
let activeEditor = vscode.window.activeTextEditor;
if (!activeEditor) { return; }
let sels = activeEditor.selections;
if (i > 0 && wasEmpty)
{
sels[i - 1] = new vscode.Selection(sels[i - 1].end, sels[i - 1].end);
activeEditor.selections = sels; // required or the selection updates will be ignored! 😱
}
if (i < 0 || i >= sels.length) { return; }
let isEmpty = sels[i].isEmpty;
activeEditor.edit(edit => edit.replace(sels[i], getText(i))).then(x => {
InsertText(getText, i + 1, isEmpty);
});
}
let strContent = "hello world";
const edit = new vscode.WorkspaceEdit();
edit.insert(YOUR_URI, new vscode.Position(0, 0), strContent);
let success = await vscode.workspace.applyEdit(edit);
I've a popover component and I added a multi-select list inside of it. I would like to set checked property to true for all items in case of the first item of list is selected. But selectionChange event works for every item's selection event. So, index value of the for loop always starts with zero. What should I do in this situation? Thanks for your suggestions.
Here is my part of a code and screenshot of image;
image url
new sap.m.List('statusTypesList', {
mode: 'MultiSelect',
selectedKeys: " ,1,2,3",
includeItemInSelection: true,
selectionChange: function(oEvent) {
var keyValues = "";
var itemArray = oEvent.oSource.getItems();
if(itemArray[0].getSelected()==true){
for (var i = 0; i < itemArray.length; i++) {
oEvent.oSource.setSelectedItem(itemArray[i], true, true);
}
}
}
})
Check if the item that fired the event is the first one in your list. Something like this:
function(oEvent) {
var changedItem = oEvent.getParameter('listItem');
if(changedItem isTheFirstItem){
//Where 'isTheFirstItem' is the condition you define to identify your first item
var keyValues = "";
var itemArray = oEvent.getSource().getItems();
if(itemArray[0].getSelected()==true){
for (var i = 0; i < itemArray.length; i++) {
oEvent.getSource().setSelectedItem(itemArray[i], true, true);
}
}
}
Define the condition you want in the if(changedItem isTheFirstItem) statement
Try this condition, maybe it works: if(changedItem === oEvent.getSource().getItems()[0])
If not, just build your own condition to check if it is the first one or not
NOTE: User getSource() to get the source from the event. It is always better than accessing the object directly
I have one SplitApp with Master -Detail layout. I would like to know how can I set the first item in Master view to default so that on loading of application Detail view shows the information about the select list item. So when user open the application automatically first item in Master should be selected and Detail View show the information.
I am using Objectlist Item as control for Master view. And currently using the select event for selecting the list item.
var oList = new sap.m.List("idMasterList",{
mode: sap.m.ListMode.SingleSelect,
select: [oController.onSelectItem, oController]
});
onSelectItem: function(oEvent){
//var app = sap.ui.getCore().byId("splitApp");
var oMasterList = sap.ui.getCore().byId("idMasterList");
var oSelItem = oMasterList.getSelectedItem();
var sPath = oSelItem.oBindingContexts.druginfo.sPath;
var oItem = sap.ui.getCore().getModel("druginfo").getProperty(sPath);
var oSelModel = new sap.ui.model.json.JSONModel(oItem) ;
sap.ui.getCore().setModel(oSelModel, "SelectedItem");
}
Regards,
Mayank
It seems like there is (hidden) API to make the select event fire when setting the selected item:
ListBase.prototype.setSelectedItem = function(oListItem, bSelect, bFireEvent) {
if (this.indexOfItem(oListItem) < 0) {
jQuery.sap.log.warning("setSelectedItem is called without valid ListItem parameter on " + this);
return;
}
if (this._bSelectionMode) {
oListItem.setSelected((bSelect === undefined) ? true : !!bSelect);
bFireEvent && this._fireSelectionChangeEvent([oListItem]);
}
};
You could use setSelectedItem once your lists data is loaded (e.g. change event of aggregation binding items) like this:
var oList = this.getView().byId("MyListID"),
oFirstItem = oList.getItems()[0];
oList.setSelectedItem(oFirstItem, true, true);
This will trigger the selectionChange resp. select event and your already existing event listener will be triggered.
I have two menus 'Setup' and 'Reports' with sub-menus 'admin users','Reports dashboard','partner dashboard','partner relationship' etc marked with red color.
I want to navigate or click using protractor locators but unable to find how to select these menus that have no id and common CSS. I want something like this
var userTypes = element.all(by.repeater('t in user_userTypes'));</br>
userTypes.get(2).click()
From what I see, these elements are navigation menu items, Setup and Reports are high-level menus and Admin Users, Reports Dashboard, Partner dashboard, Partner Relationship and Grading Data are submenus. To open a submenu, I assume, you should click the appropriate menu.
Let's make a reusable function that would accept a menu label and a desired submenu label and use by.repeater() locator filtering the menus by text:
function selectMenu(menuLabel, submenuLabel) {
var menu = element.all(by.repeater("mi in menuItems")).filter(function (menu) {
return menu.all(by.tagName("a")).first().getText().then(function (text) {
return text.indexOf(menuLabel) === 0;
});
}).first();
menu.click(); // open up menu
var submenu = menu.all(by.repeater("s in mi.subMenuItems")).filter(function (submenu) {
return submenu.all(by.tagName("a")).first().getText().then(function (text) {
return text.indexOf(submenuLabel) === 0;
});
}).first();
submenu.click(); // select submenu
}
Usage samples:
selectMenu("Setup", "Admin Users");
selectMenu("Reports", "Reports Dashboard");
Define a method and pass the 'hrefValue', filter by anchor tag.
var clickParticular = function(hrefValue){
element.all(by.tagName('a')).filter(function(element, index) {
return element.getAttribute('href').then(function (text) {
return text === hrefValue;
});
}).then(function(filteredElements) {
filteredElements[0].click().then(function() {
});
});
}