Merge pull request #13805 from NissimHadar/exportToTestRail1

Auto-Tester export to TestRail
This commit is contained in:
Sam Gateau 2018-08-10 14:40:12 -07:00 committed by GitHub
commit 9cb0c36d90
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 1508 additions and 342 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

197
tools/auto-tester/README.md Normal file
View file

@ -0,0 +1,197 @@
# Auto Tester
The auto-tester is a stand alone application that provides a mechanism for regression testing. The general idea is simple:
* Each test folder has a script that produces a set of snapshots.
* The snapshots are compared to a 'canonical' set of images that have been produced beforehand.
* The result, if any test failed, is a zipped folder describing the failure.
Auto-tester has 4 functions, separated into 4 tabs:
1. Creating tests, MD files and recursive scripts
2. Evaluating the results of running tests
3. TestRail interface
4. Windows task bar utility (Windows only)
## Installation
### Executable
1. Download the installer by browsing to [here](<https://hifi-content.s3.amazonaws.com/nissim/autoTester/AutoTester-Installer.exe>).
2. Double click on the installer and install to a convenient location
![](./setup_7z.PNG)
3. To run the auto-tester, double click **auto-tester.exe**.
### Python
The TestRail interface requires Python 3 to be installed. Auto-Tester has been tested with Python 3.7.0 but should work with newer versions.
Python 3 can be downloaded from:
1. Windows installer <https://www.python.org/downloads/>
2. Linux (source) <https://www.python.org/downloads/release/python-370/> (**Gzipped source tarball**)
3. Mac <https://www.python.org/downloads/release/python-370/> (**macOS 64-bit/32-bit installer** or **macOS 64-bit/32-bit installer**)
After installation - create an environment variable called PYTHON_PATH and set it to the folder containing the Python executable.
# Create
![](./Create.PNG)
The Create tab provides functions to create tests from snapshots, MD files, a test outline and recursive scripts.
## Create Tests
### Usage
This function is used to create/update Expected Images after a successful run of a test, or multiple tests.
The user will be asked for the snapshot folder and then the tests root folder. All snapshots located in the snapshot folder will be used to create or update the expected images in the relevant tests.
### Details
As an example - if the snapshots folder contains an image named `tests.content.entity.zone.zoneOrientation.00003.png`, then this file will be copied to `tests/contente/enity/zone/zoneOrientation/ExpectedImage0003.png`.
## Create MD file
### Usage
This function creates a file named `test.md` from a `test.js` script. The user will be asked for the folder containing the test script:
### Details
The process to produce the MD file is a simplistic parse of the test script.
- The string in the `autoTester.perform(...)` function call will be the title of the file
- Instructions to run the script are then provided:
**Run this script URL: [Manual]() [Auto]()(from menu/Edit/Open and Run scripts from URL...).**
- The step description is the string in the addStep/addStepStepSnapshot commands
- Image links are provided where applicable to the local Expected Images files
## Create all MD files
### Usage
This function creates all MD files recursively from the user-selected root folder. This can be any folder in the tests hierarchy (e.g. all engine\material tests).
The file provides a hierarchial list of all the tests
## Create Tests Outline
### Usage
This function creates an MD file in the (user-selected) tests root folder. The file provides links to both the tests and the MD files.
## Create Recursive Script
### Usage
After the user selects a folder within the tests hierarchy, a script is created, named `testRecursive.js`. This script calls all `test.js` scripts in the subfolders.
### Details
The various scripts are called in alphabetical order.
An example of a recursive script is as follows:
```
// This is an automatically generated file, created by auto-tester on Jul 5 2018, 10:19
PATH_TO_THE_REPO_PATH_UTILS_FILE = "https://raw.githubusercontent.com/highfidelity/hifi_tests/master/tests/utils/branchUtils.js";
Script.include(PATH_TO_THE_REPO_PATH_UTILS_FILE);
var autoTester = createAutoTester(Script.resolvePath("."));
var testsRootPath = autoTester.getTestsRootPath();
if (typeof Test !== 'undefined') {
Test.wait(10000);
};
autoTester.enableRecursive();
autoTester.enableAuto();
Script.include(testsRootPath + "content/overlay/layer/drawInFront/shape/test.js");
Script.include(testsRootPath + "content/overlay/layer/drawInFront/model/test.js");
Script.include(testsRootPath + "content/overlay/layer/drawHUDLayer/test.js");
autoTester.runRecursive();
```
## Create all Recursive Scripts
### Usage
In this case all recursive scripts, from the selected folder down, are created.
Running this function in the tests root folder will create (or update) all the recursive scripts.
# Evaluate
![](./Evaluate.PNG)
The Evaluate tab provides a single function - evaluating the results of a test run.
A checkbox (defaulting to checked) runs the evaluation in interactive mode. In this mode - every failure is shown to the user, who can then decide whether to pass the test, fail it or abort the whole evaluation.
If any tests have failed, then a zipped folder will be created in the snapshots folder, with a description of each failed step in each test.
### Usage
Before starting the evaluation, make sure the GitHub user and branch are set correctly. The user should not normally be changed, but the branch may need to be set to the appropriate RC.
After setting the checkbox as required and pressing Evaluate - the user will be asked for the snapshots folder.
### Details
Evaluation proceeds in a number of steps:
1. A folder is created to store any failures
1. The expecetd images are download from GitHub. They are named slightly differently from the snapshots (e.g. `tests.engine.render.effect.highlight.coverage.00000.png` and `tests.engine.render.effect.highlight.coverage.00000_EI.png`).
1. The images are then pair-wise compared, using the SSIM algorithm. A fixed threshold is used to define a mismatch.
1. In interactive mode - a window is opened showing the expected image, actual image, difference image and error:
![](./autoTesterMismatchExample.PNG)
1. If not in interactive mode, or the user has defined the results as an error, an error is written into the error folder. The error itself is a folder with the 3 images and a small text file containing details.
1. At the end of the test, the folder is zipped and the original folder is deleted. If there are no errors then the zipped folder will be empty.
# TestRail
![](./TestRail.PNG)
Before updating TestRail, make sure the GitHub user and branch are set correctly. The user should not normally be changed, but the branch may need to be set to the appropriate RC.
Any access to TestRail will require the TestRail account (default is High Fidelity's account), a user-name and a password:
![](./TestRailSelector.PNG)
- The default test rail user is shown, and can be changed as needed.
- The username is usually the user's email.
- The Project ID defaults to 14 - Interface.
- The Suite ID defaults to 1147 - Renderong.
- The TestRail page provides 3 functions for writing to TestRail.
## Create Test Cases
### Usage
This function can either create an XML file that can then be imported into TestRail through TestRail itself, or automatically create the appropriate TestRail Sections.
The user will be first asked for the tests root folder and a folder to store temporary files (this is the output folder).
If XML has been selected, then the XML file will be created in the output folder.
If Python is selected, the user will then be prompted for TestRail data. After pressing `Accept` - the Release combo will be populated (as it needs to be read from TestRail).
After selecting the appropriate Release, press OK. The Python script will be created in the output folder, and the user will be prompted to run it.
A busy window will appear until the process is complete.
### Details
A number of Python scripts are created:
- `testrail.py` is the TestRail interface code.
- `stack.py` is a simple stack class
- `getReleases.py` reads the release names from TestRail
- `addTestCases` is the script that writes to TestRail.
In addition - a file containing all the releases will be created - `releases.txt`
## Create Run
A Run is created from previously created Test Cases.
The user will first be prompted for a temporary folder (for the Python scripts).
After entering TestRail data and pressing `Accept` - the Sections combo will be populated (as it needs to be read from TestRail).
After selecting the appropriate Section, press OK. The Python script will be created in the output folder, and the user will be prompted to run it.
A busy window will appear until the process is complete.
### Details
A number of Python scripts are created:
- `testrail.py` is the TestRail interface code.
- `stack.py` is a simple stack class
- `getSections.py` reads the release names from TestRail
- `addRun` is the script that writes to TestRail.
In addition - a file containing all the releases will be created - `sections.txt`
## Update Run Results
This function updates a Run with the results of an automated test.
The user will first be prompted to enter the zipped results folder and a folder to store temporary files (this is the output folder).
After entering TestRail data and pressing `Accept` - the Run combo will be populated (as it needs to be read from TestRail).
After selecting the appropriate Run, press OK. The Python script will be created in the output folder, and the user will be prompted to run it.
A busy window will appear until the process is complete.
### Details
A number of Python scripts are created:
- `testrail.py` is the TestRail interface code.
- `getRuns.py` reads the release names from TestRail
- `addRun` is the script that writes to TestRail.
In addition - a file containing all the releases will be created - `runs.txt`
# Windows
![](./Windows.PNG)
This tab is Windows-specific. It provides buttons to hide and show the task bar.
The task bar should be hidden for all tests that use the primary camera. This is required to ensure that the snapshots are the right size.

View file

@ -1,7 +0,0 @@
After building auto-tester, it needs to be deployed to Amazon SW
* In folder hifi/build/tools/auto-tester
* Right click on the Release folder
* Select 7-Zip -> Add to archive
* Select Option ```Create SFX archive``` to create Release.exe
* Use Cyberduck (or any other AWS S3 client) to copy Release.exe to hifi-content/nissim/autoTester/

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -27,8 +27,8 @@ Test::Test() {
_mismatchWindow.setModal(true);
if (autoTester) {
autoTester->setUserText("highfidelity");
autoTester->setBranchText("master");
autoTester->setUserText(GIT_HUB_DEFAULT_USER);
autoTester->setBranchText(GIT_HUB_DEFAULT_BRANCH);
}
}
@ -49,9 +49,7 @@ void Test::zipAndDeleteTestResultsFolder() {
}
QDir testResultsFolder(_testResultsFolderPath);
if (!testResultsFolder.isEmpty()) {
JlCompress::compressDir(_testResultsFolderPath + ".zip", _testResultsFolderPath);
}
JlCompress::compressDir(_testResultsFolderPath + ".zip", _testResultsFolderPath);
testResultsFolder.removeRecursively();
@ -132,9 +130,7 @@ void Test::appendTestResultsToFile(const QString& _testResultsFolderPath, TestFa
exit(-1);
}
QString err = QString::number(testFailure._error).left(6);
QString failureFolderPath { _testResultsFolderPath + "/" + err + "-Failure_" + QString::number(_index) + "--" + testFailure._actualImageFilename.left(testFailure._actualImageFilename.length() - 4) };
QString failureFolderPath { _testResultsFolderPath + "/Failure_" + QString::number(_index) + "--" + testFailure._actualImageFilename.left(testFailure._actualImageFilename.length() - 4) };
if (!QDir().mkdir(failureFolderPath)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create folder " + failureFolderPath);
exit(-1);
@ -832,7 +828,7 @@ void Test::createTestRailTestCases() {
QFileDialog::getExistingDirectory(nullptr, "Please select the tests root folder", parent, QFileDialog::ShowDirsOnly);
// If user cancelled then restore previous selection and return
if (_testDirectory == "") {
if (_testDirectory.isNull()) {
_testDirectory = previousSelection;
return;
}
@ -841,7 +837,7 @@ void Test::createTestRailTestCases() {
nullptr, QFileDialog::ShowDirsOnly);
// If user cancelled then return
if (outputDirectory == "") {
if (outputDirectory.isNull()) {
return;
}
@ -857,9 +853,30 @@ void Test::createTestRailTestCases() {
void Test::createTestRailRun() {
QString outputDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select a folder to store generated files in",
nullptr, QFileDialog::ShowDirsOnly);
if (outputDirectory.isNull()) {
return;
}
_testRailInterface.createTestRailRun(outputDirectory);
}
void Test::updateTestRailRunResult() {
QString testResults = QFileDialog::getOpenFileName(nullptr, "Please select the zipped test results to update from", nullptr,
"Zipped Test Results (*.zip)");
if (testResults.isNull()) {
return;
}
QString tempDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select a folder to store temporary files in",
nullptr, QFileDialog::ShowDirsOnly);
if (tempDirectory.isNull()) {
return;
}
_testRailInterface.updateTestRailRunResults(testResults, tempDirectory);
}
QStringList Test::createListOfAll_imagesInDirectory(const QString& imageFormat, const QString& pathToImageDirectory) {
_imageDirectory = QDir(pathToImageDirectory);
QStringList nameFilters;

View file

@ -51,14 +51,16 @@ public:
void createRecursiveScript(const QString& topLevelDirectory, bool interactiveMode);
void createTests();
void createTestsOutline();
void createMDFile();
void createAllMDFiles();
void createMDFile(const QString& topLevelDirectory);
void createTestsOutline();
void createTestRailTestCases();
void createTestRailRun();
void updateTestRailRunResult();
bool compareImageLists(bool isInteractiveMode, QProgressBar* progressBar);
@ -115,6 +117,8 @@ private:
QStringList _resultImagesFullFilenames;
// Used for accessing GitHub
const QString GIT_HUB_DEFAULT_USER{ "highfidelity" };
const QString GIT_HUB_DEFAULT_BRANCH{ "master" };
const QString GIT_HUB_REPOSITORY{ "hifi_tests" };
const QString DATETIME_FORMAT{ "yyyy-MM-dd_hh-mm-ss" };

View file

@ -11,6 +11,9 @@
#include "TestRailInterface.h"
#include "Test.h"
#include <quazip5/quazip.h>
#include <quazip5/JlCompress.h>
#include <QDateTime>
#include <QFile>
#include <QMessageBox>
@ -20,22 +23,35 @@ TestRailInterface::TestRailInterface() {
_testRailTestCasesSelectorWindow.setURL("https://highfidelity.testrail.net");
////_testRailTestCasesSelectorWindow.setURL("https://nissimhadar.testrail.io");
_testRailTestCasesSelectorWindow.setUser("@highfidelity.io");
////_testRailSelectorWindow.setUser("nissim.hadar@gmail.com");
////_testRailTestCasesSelectorWindow.setUser("nissim.hadar@gmail.com");
_testRailTestCasesSelectorWindow.setProjectID(INTERFACE_PROJECT_ID);
////_testRailSelectorWindow.setProject(1);
////_testRailTestCasesSelectorWindow.setProjectID(2);
_testRailTestCasesSelectorWindow.setSuiteID(INTERFACE_SUITE_ID);
////_testRailTestCasesSelectorWindow.setSuiteID(2);
_testRailRunSelectorWindow.setURL("https://highfidelity.testrail.net");
////_testRailRunSelectorWindow.setURL("https://nissimhadar.testrail.io");
_testRailRunSelectorWindow.setUser("@highfidelity.io");
////_testRailSelectorWindow.setUser("nissim.hadar@gmail.com");
////_testRailRunSelectorWindow.setUser("nissim.hadar@gmail.com");
_testRailRunSelectorWindow.setProjectID(INTERFACE_PROJECT_ID);
////_testRailSelectorWindow.setProject(1);
////_testRailRunSelectorWindow.setProjectID(2);
_testRailRunSelectorWindow.setSuiteID(INTERFACE_SUITE_ID);
////_testRailRunSelectorWindow.setSuiteID(2);
_testRailResultsSelectorWindow.setURL("https://highfidelity.testrail.net");
////_testRailResultsSelectorWindow.setURL("https://nissimhadar.testrail.io");
_testRailResultsSelectorWindow.setUser("@highfidelity.io");
////_testRailResultsSelectorWindow.setUser("nissim.hadar@gmail.com");
_testRailResultsSelectorWindow.setProjectID(INTERFACE_PROJECT_ID);
////_testRailResultsSelectorWindow.setProjectID(2);
_testRailResultsSelectorWindow.setSuiteID(INTERFACE_SUITE_ID);
////_testRailResultsSelectorWindow.setSuiteID(2);
}
QString TestRailInterface::getObject(const QString& path) {
@ -212,21 +228,59 @@ void TestRailInterface::createStackDotPyScript() {
file.close();
}
void TestRailInterface::requestTestRailTestCasesDataFromUser() {
bool TestRailInterface::requestTestRailTestCasesDataFromUser() {
// Make sure correct fields are enabled before calling
_testRailTestCasesSelectorWindow.reset();
_testRailTestCasesSelectorWindow.exec();
if (_testRailTestCasesSelectorWindow.getUserCancelled()) {
return;
return false;
}
_url = _testRailTestCasesSelectorWindow.getURL() + "/";
_user = _testRailTestCasesSelectorWindow.getUser();
_password = _testRailTestCasesSelectorWindow.getPassword();
////_password = "tutKA76";
////_password = "tutKA76";////
_projectID = QString::number(_testRailTestCasesSelectorWindow.getProjectID());
_suiteID = QString::number(_testRailTestCasesSelectorWindow.getSuiteID());
return true;
}
bool TestRailInterface::requestTestRailRunDataFromUser() {
_testRailRunSelectorWindow.reset();
_testRailRunSelectorWindow.exec();
if (_testRailRunSelectorWindow.getUserCancelled()) {
return false;
}
_url = _testRailRunSelectorWindow.getURL() + "/";
_user = _testRailRunSelectorWindow.getUser();
_password = _testRailRunSelectorWindow.getPassword();
////_password = "tutKA76";////
_projectID = QString::number(_testRailRunSelectorWindow.getProjectID());
_suiteID = QString::number(_testRailRunSelectorWindow.getSuiteID());
return true;
}
bool TestRailInterface::requestTestRailResultsDataFromUser() {
_testRailResultsSelectorWindow.reset();
_testRailResultsSelectorWindow.exec();
if (_testRailResultsSelectorWindow.getUserCancelled()) {
return false;
}
_url = _testRailResultsSelectorWindow.getURL() + "/";
_user = _testRailResultsSelectorWindow.getUser();
_password = _testRailResultsSelectorWindow.getPassword();
////_password = "tutKA76";////
_projectID = QString::number(_testRailResultsSelectorWindow.getProjectID());
_suiteID = QString::number(_testRailResultsSelectorWindow.getSuiteID());
return true;
}
bool TestRailInterface::isAValidTestDirectory(const QString& directory) {
@ -307,7 +361,7 @@ void TestRailInterface::createAddTestCasesPythonScript(const QString& testDirect
// top-level section
stream << "data = { 'name': '"
<< "Test Suite - " << QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm") + "', "
<< "Test Section - " << QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm") + "', "
<< "'suite_id': " + _suiteID + "}\n";
stream << "section = client.send_post('add_section/' + str(" << _projectID << "), data)\n";
@ -320,8 +374,8 @@ void TestRailInterface::createAddTestCasesPythonScript(const QString& testDirect
if (QMessageBox::Yes == QMessageBox(QMessageBox::Information, "Python script has been created",
"Do you want to run the script and update TestRail?",
QMessageBox::Yes | QMessageBox::No)
.exec()) {
QMessageBox::Yes | QMessageBox::No).exec()
) {
QProcess* process = new QProcess();
connect(process, &QProcess::started, this, [=]() { _busyWindow.exec(); });
@ -333,7 +387,7 @@ void TestRailInterface::createAddTestCasesPythonScript(const QString& testDirect
}
}
void TestRailInterface::updateMilestonesComboData(int exitCode, QProcess::ExitStatus exitStatus) {
void TestRailInterface::updateReleasesComboData(int exitCode, QProcess::ExitStatus exitStatus) {
// Quit if user has previously cancelled
if (_testRailTestCasesSelectorWindow.getUserCancelled()) {
return;
@ -342,41 +396,38 @@ void TestRailInterface::updateMilestonesComboData(int exitCode, QProcess::ExitSt
// Check if process completed successfully
if (exitStatus != QProcess::NormalExit) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not get milestones from TestRail");
"Could not get 'added to release' data from TestRail");
exit(-1);
}
// Create map of milestones from the file created by the process
_milestoneNames.clear();
// Create map of releases from the file created by the process
_releaseNames.clear();
QString filename = _outputDirectory + "/milestones.txt";
QString filename = _outputDirectory + "/releases.txt";
if (!QFile::exists(filename)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not find milestones.txt in " + _outputDirectory);
"Could not find releases.txt in " + _outputDirectory);
exit(-1);
}
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not open " + _outputDirectory + "/milestones.txt");
"Could not open " + _outputDirectory + "/releases.txt");
exit(-1);
}
QTextStream in(&file);
QString line = in.readLine();
while (!line.isNull()) {
QStringList words = line.split(' ');
_milestones[words[0]] = words[1].toInt();
_milestoneNames << words[0];
_releaseNames << line;
line = in.readLine();
}
file.close();
// Update the combo
_testRailTestCasesSelectorWindow.updateMilestonesComboBoxData(_milestoneNames);
_testRailTestCasesSelectorWindow.updateReleasesComboBoxData(_releaseNames);
_testRailTestCasesSelectorWindow.exec();
@ -387,6 +438,167 @@ void TestRailInterface::updateMilestonesComboData(int exitCode, QProcess::ExitSt
createAddTestCasesPythonScript(_testDirectory, _userGitHub, _branchGitHub);
}
void TestRailInterface::addRun() {
QString filename = _outputDirectory + "/addRun.py";
if (QFile::exists(filename)) {
QFile::remove(filename);
}
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not create " + filename);
exit(-1);
}
QTextStream stream(&file);
// Code to access TestRail
stream << "from testrail import *\n";
stream << "client = APIClient('" << _url.toStdString().c_str() << "')\n";
stream << "client.user = '" << _user << "'\n";
stream << "client.password = '" << _password << "'\n\n";
// A test suite is a forest. Each node is a section and leaves are either sections or test cases
// The user has selected a root for the run
// To find the cases in this tree we need all the sections in the tree
// These are found by building a set of all relevant sections. The first section is the selected root
// As the sections are in an ordered array we use the following snippet to find the relevant sections:
// initialize section set with the root
// for each section in the ordered array of sections in the suite
// if the parent of the section is in the section set then
// add this section to the section set
//
stream << "sections = client.send_get('get_sections/" + _projectID + "&suite_id=" + _suiteID + "')\n\n";
int sectionID = _sectionIDs[_testRailRunSelectorWindow.getSectionID()];
stream << "relevantSections = { " + QString::number(sectionID) + " }\n";
stream << "for section in sections:\n";
stream << "\tif section['parent_id'] in relevantSections:\n";
stream << "\t\trelevantSections.add(section['id'])\n\n";
// We now loop over each section in the set and collect the cases into an array
stream << "cases = []\n";
stream << "for section_id in relevantSections:\n";
stream << "\tcases = cases + client.send_get('get_cases/" + _projectID + "&suite_id=" + _suiteID + "&section_id=' + str(section_id))\n\n";
// To create a run we need an array of the relevant case ids
stream << "case_ids = []\n";
stream << "for case in cases:\n";
stream << "\tcase_ids.append(case['id'])\n\n";
// Now, we can create the run
stream << "data = { 'name': '" + _sectionNames[_testRailRunSelectorWindow.getSectionID()].replace("Section", "Run") +
"', 'suite_id': " + _suiteID +
", 'include_all': False, 'case_ids': case_ids}\n";
stream << "run = client.send_post('add_run/" + _projectID + "', data)\n";
file.close();
if (QMessageBox::Yes == QMessageBox(QMessageBox::Information, "Python script has been created",
"Do you want to run the script and update TestRail?",
QMessageBox::Yes | QMessageBox::No).exec()
) {
QProcess* process = new QProcess();
connect(process, &QProcess::started, this, [=]() { _busyWindow.exec(); });
connect(process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this,
[=](int exitCode, QProcess::ExitStatus exitStatus) { _busyWindow.hide(); });
QStringList parameters = QStringList() << _outputDirectory + "/addRun.py";
process->start(_pythonCommand, parameters);
}
}
void TestRailInterface::updateRunWithResults() {
QString filename = _outputDirectory + "/updateRunWithResults.py";
if (QFile::exists(filename)) {
QFile::remove(filename);
}
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not create " + filename);
exit(-1);
}
QTextStream stream(&file);
// Code to access TestRail
stream << "from testrail import *\n";
stream << "client = APIClient('" << _url.toStdString().c_str() << "')\n";
stream << "client.user = '" << _user << "'\n";
stream << "client.password = '" << _password << "'\n\n";
// It is assumed that all the tests that haven't failed have passed
// The failed tests are read, formatted and inserted into a set
// A failure named 'Failure_1--tests.content.entity.material.apply.avatars.00000' is formatted to 'content/entity/material/apply/avatars'
// This is the name of the test in TestRail
stream << "from os import listdir\n";
stream << "failed_tests = set()\n";
stream << "for entry in listdir('" + _outputDirectory + "/" + tempName + "'):\n";
stream << "\tparts = entry.split('--tests.')[1].split('.')\n";
stream << "\tfailed_test = parts[0]\n";
stream << "\tfor i in range(1, len(parts) - 1):\n";
stream << "\t\tfailed_test = failed_test + '/' + parts[i]\n";
stream << "\tfailed_tests.add(failed_test)\n\n";
// Initialize the array of results that will be eventually used to update TestRail
stream << "status_ids = []\n";
stream << "case_ids = []\n";
int runID = _runIDs[_testRailResultsSelectorWindow.getRunID()];
stream << "tests = client.send_get('get_tests/" + QString::number(runID) + "')\n\n";
stream << "for test in tests:\n";
// status_id's: 1 - Passed
// 2 - Blocked
// 3 - Untested
// 4 - Retest
// 5 - Failed
stream << "\tstatus_id = 1\n";
stream << "\tif test['title'] in failed_tests:\n";
stream << "\t\tstatus_id = 5\n";
stream << "\tcase_ids.append(test['case_id'])\n";
stream << "\tstatus_ids.append(status_id)\n\n";
// We can now update the test (note that all tests need to be updated)
// An example request is as follows:
//
// "results" : [
// { 'case_id': 1, 'status_id': 5 },
// { 'case_id': 2, 'status_id': 1 }
// ]
//
stream << "results = []\n";
stream << "for i in range(len(case_ids)):\n";
stream << "\tresults.append({'case_id': case_ids[i], 'status_id': status_ids[i] })\n\n";
stream << "data = { 'results': results }\n";
stream << "section = client.send_post('add_results_for_cases/' + str(" << runID << "), data)\n";
file.close();
if (QMessageBox::Yes == QMessageBox(QMessageBox::Information, "Python script has been created",
"Do you want to run the script and update TestRail?",
QMessageBox::Yes | QMessageBox::No).exec()
) {
QProcess* process = new QProcess();
connect(process, &QProcess::started, this, [=]() { _busyWindow.exec(); });
connect(process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this,
[=](int exitCode, QProcess::ExitStatus exitStatus) { _busyWindow.hide(); });
QStringList parameters = QStringList() << _outputDirectory + "/updateRunWithResults.py";
process->start(_pythonCommand, parameters);
}
}
void TestRailInterface::updateSectionsComboData(int exitCode, QProcess::ExitStatus exitStatus) {
// Quit if user has previously cancelled
if (_testRailRunSelectorWindow.getUserCancelled()) {
@ -413,7 +625,7 @@ void TestRailInterface::updateSectionsComboData(int exitCode, QProcess::ExitStat
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not open " + _outputDirectory + "/sections.txt");
"Could not open " + filename);
exit(-1);
}
@ -425,7 +637,7 @@ void TestRailInterface::updateSectionsComboData(int exitCode, QProcess::ExitStat
QString section = line.left(line.lastIndexOf(" "));
QString id = line.right(line.length() - line.lastIndexOf(" ") - 1);
_sections[section] = id.toInt();
_sectionIDs.push_back(id.toInt());
_sectionNames << section;
line = in.readLine();
@ -442,11 +654,73 @@ void TestRailInterface::updateSectionsComboData(int exitCode, QProcess::ExitStat
return;
}
////createAddTestCasesPythonScript(_testDirectory, _userGitHub, _branchGitHub);
// The test cases are now read from TestRail
// When this is complete, the Run can be created
addRun();
}
void TestRailInterface::getMilestonesFromTestRail() {
QString filename = _outputDirectory + "/getMilestones.py";
void TestRailInterface::updateRunsComboData(int exitCode, QProcess::ExitStatus exitStatus) {
// Quit if user has previously cancelled
if (_testRailRunSelectorWindow.getUserCancelled()) {
return;
}
// Check if process completed successfully
if (exitStatus != QProcess::NormalExit) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not get runs from TestRail");
exit(-1);
}
// Create map of sections from the file created by the process
_runNames.clear();
QString filename = _outputDirectory + "/runs.txt";
if (!QFile::exists(filename)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not find runs.txt in " + _outputDirectory);
exit(-1);
}
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not open " + filename);
exit(-1);
}
QTextStream in(&file);
QString line = in.readLine();
while (!line.isNull()) {
// The run name is all the words except for the last
// The id is the last word
QString section = line.left(line.lastIndexOf(" "));
QString id = line.right(line.length() - line.lastIndexOf(" ") - 1);
_runIDs.push_back(id.toInt());
_runNames << section;
line = in.readLine();
}
file.close();
// Update the combo
_testRailResultsSelectorWindow.updateRunsComboBoxData(_runNames);
_testRailResultsSelectorWindow.exec();
if (_testRailResultsSelectorWindow.getUserCancelled()) {
return;
}
// The test cases are now read from TestRail
// When this is complete, the Run can be updated
updateRunWithResults();
}
void TestRailInterface::getReleasesFromTestRail() {
QString filename = _outputDirectory + "/getReleases.py";
if (QFile::exists(filename)) {
QFile::remove(filename);
}
@ -454,7 +728,7 @@ void TestRailInterface::getMilestonesFromTestRail() {
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not create 'getMilestones.py'");
"Could not create 'getReleases.py'");
exit(-1);
}
@ -466,21 +740,33 @@ void TestRailInterface::getMilestonesFromTestRail() {
stream << "client.user = '" << _user << "'\n";
stream << "client.password = '" << _password << "'\n\n";
// Print the list of uncompleted milestones
stream << "file = open('" + _outputDirectory + "/milestones.txt', 'w')\n\n";
stream << "milestones = client.send_get('get_milestones/" + _projectID + "')\n";
stream << "for milestone in milestones:\n";
stream << "\tif milestone['is_completed'] == False:\n";
stream << "\t\tfile.write(milestone['name'] + ' ' + str(milestone['id']) + '\\n')\n\n";
// Print the list of releases
stream << "case_fields = client.send_get('get_case_fields/" + _projectID + "')\n";
stream << "for case_field in case_fields:\n";
stream << "\tif case_field['name'] == 'added_to_release':\n";
stream << "\t\trelease_string = case_field['configs'][0]['options']['items']\n\n";
// The list read from TestRail looks like this:
// '0,< RC65\n1,RC65\n2,RC66\n3,RC67\n4,RC68\n5,RC69\n6,v0.70.0\n7,v0.71.0\n8,v0.72.0\n9,v0.73.0\n10,v0.74.0\n11,v0.75.0\n12,v0.76.0\n13,v0.77.0\n14,v0.78.0\n15,v0.79.0'
// Splitting on newline gives an array:
// ['0,< RC65', '1,RC65', '2,RC66', '3,RC67', '4,RC68', '5,RC69', '6,v0.70.0', '7,v0.71.0', '8,v0.72.0', '9,v0.73.0', '10,v0.74.0', '11,v0.75.0', '12,v0.76.0', '13,v0.77.0', '14,v0.78.0', '15,v0.79.0']
// Each element consists of an index and a string, separated by a comma.
// We just need the strings
stream << "file = open('" + _outputDirectory + "/releases.txt', 'w')\n\n";
stream << "releases = release_string.split('\\n')\n";
stream << "for release in releases:\n";
stream << "\twords = release.split(',')\n";
stream << "\tfile.write(words[1] + '\\n')\n\n";
stream << "file.close()\n";
file.close();
QProcess* process = new QProcess();
connect(process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this,
[=](int exitCode, QProcess::ExitStatus exitStatus) { updateMilestonesComboData(exitCode, exitStatus); });
[=](int exitCode, QProcess::ExitStatus exitStatus) { updateReleasesComboData(exitCode, exitStatus); });
QStringList parameters = QStringList() << _outputDirectory + "/getMilestones.py ";
QStringList parameters = QStringList() << filename;
process->start(_pythonCommand, parameters);
}
@ -497,12 +783,15 @@ void TestRailInterface::createTestSuitePython(const QString& testDirectory,
return;
}
requestTestRailTestCasesDataFromUser();
if (!requestTestRailTestCasesDataFromUser()) {
return;
}
createTestRailDotPyScript();
createStackDotPyScript();
// TestRail will be updated after the process initiated by getMilestonesFromTestRail has completed
getMilestonesFromTestRail();
// TestRail will be updated after the process initiated by getReleasesFromTestRail has completed
getReleasesFromTestRail();
}
void TestRailInterface::createTestSuiteXML(const QString& testDirectory,
@ -747,15 +1036,13 @@ void TestRailInterface::processTestPython(const QString& fullDirectory,
QString testContent = QString("Execute instructions in [THIS TEST](") + testMDName + ")";
QString testExpected = QString("Refer to the expected result in the linked description.");
int milestone_id = _milestones[_milestoneNames[_testRailTestCasesSelectorWindow.getMilestoneID()]];
stream << "data = {\n"
<< "\t'title': '" << title << "',\n"
<< "\t'template_id': 2,\n"
<< "\t'milestone_id': " << milestone_id << ",\n"
<< "\t'custom_added_to_release': " << _testRailTestCasesSelectorWindow.getReleaseID() << ",\n"
<< "\t'custom_tester_count': 1,\n"
<< "\t'custom_domain_bot_load': 1,\n"
<< "\t'custom_added_to_release': 4,\n"
<< "\t'custom_preconds': "
<< "'Tester is in an empty region of a domain in which they have edit rights\\n\\n*Note: Press \\'n\\' to advance "
"test script',\n"
@ -766,22 +1053,6 @@ void TestRailInterface::processTestPython(const QString& fullDirectory,
stream << "case = client.send_post('add_case/' + str(section_id), data)\n";
}
void TestRailInterface::requestTestRailRunDataFromUser() {
_testRailRunSelectorWindow.reset();
_testRailRunSelectorWindow.exec();
if (_testRailRunSelectorWindow.getUserCancelled()) {
return;
}
_url = _testRailRunSelectorWindow.getURL() + "/";
_user = _testRailRunSelectorWindow.getUser();
_password = _testRailRunSelectorWindow.getPassword();
////_password = "tutKA76";
_projectID = QString::number(_testRailRunSelectorWindow.getProjectID());
_suiteID = QString::number(_testRailRunSelectorWindow.getSuiteID());
}
void TestRailInterface::getTestSectionsFromTestRail() {
QString filename = _outputDirectory + "/getSections.py";
if (QFile::exists(filename)) {
@ -817,7 +1088,46 @@ void TestRailInterface::getTestSectionsFromTestRail() {
connect(process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this,
[=](int exitCode, QProcess::ExitStatus exitStatus) { updateSectionsComboData(exitCode, exitStatus); });
QStringList parameters = QStringList() << _outputDirectory + "/getSections.py ";
QStringList parameters = QStringList() << filename;
process->start(_pythonCommand, parameters);
}
void TestRailInterface::getRunsFromTestRail() {
QString filename = _outputDirectory + "/getRuns.py";
if (QFile::exists(filename)) {
QFile::remove(filename);
}
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not create " + filename);
exit(-1);
}
QTextStream stream(&file);
// Code to access TestRail
stream << "from testrail import *\n";
stream << "client = APIClient('" << _url.toStdString().c_str() << "')\n";
stream << "client.user = '" << _user << "'\n";
stream << "client.password = '" << _password << "'\n\n";
// Print the list of runs
stream << "runs = client.send_get('get_runs/" + _projectID + "')\n\n";
stream << "file = open('" + _outputDirectory + "/runs.txt', 'w')\n\n";
stream << "for run in runs:\n";
stream << "\tfile.write(run['name'] + ' ' + str(run['id']) + '\\n')\n\n";
stream << "file.close()\n";
file.close();
QProcess* process = new QProcess();
connect(process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this,
[=](int exitCode, QProcess::ExitStatus exitStatus) { updateRunsComboData(exitCode, exitStatus); });
QStringList parameters = QStringList() << filename;
process->start(_pythonCommand, parameters);
}
@ -828,10 +1138,37 @@ void TestRailInterface::createTestRailRun(const QString& outputDirectory) {
return;
}
requestTestRailRunDataFromUser();
if (!requestTestRailRunDataFromUser()) {
return;
}
createTestRailDotPyScript();
createStackDotPyScript();
// TestRail will be updated after the process initiated by getTestCasesFromTestRail has completed
getTestSectionsFromTestRail();
}
void TestRailInterface::updateTestRailRunResults(const QString& testResults, const QString& tempDirectory) {
_outputDirectory = tempDirectory;
if (!setPythonCommand()) {
return;
}
if (!requestTestRailResultsDataFromUser()) {
return;
}
// This is needed to access TestRail
createTestRailDotPyScript();
// Extract test failures from zipped folder
QString tempSubDirectory = tempDirectory + "/" + tempName;
QDir dir = tempSubDirectory;
dir.mkdir(tempSubDirectory);
JlCompress::extractDir(testResults, tempSubDirectory);
// TestRail will be updated after the process initiated by getTestRunFromTestRail has completed
getRunsFromTestRail();
}

View file

@ -15,6 +15,7 @@
#include "ui/TestRailTestCasesSelectorWindow.h"
#include "ui/TestRailRunSelectorWindow.h"
#include "ui/TestRailResultsSelectorWindow.h"
#include <QDirIterator>
#include <QtXml/QDomDocument>
@ -53,14 +54,16 @@ public:
const QString& userGitHub,
const QString& branchGitHub);
void getMilestonesFromTestRail();
void getReleasesFromTestRail();
void getTestSectionsFromTestRail();
void getRunsFromTestRail();
void createTestRailDotPyScript();
void createStackDotPyScript();
void requestTestRailTestCasesDataFromUser();
void requestTestRailRunDataFromUser();
bool requestTestRailTestCasesDataFromUser();
bool requestTestRailRunDataFromUser();
bool requestTestRailResultsDataFromUser();
void createAddTestCasesPythonScript(const QString& testDirectory,
const QString& userGitHub,
@ -75,10 +78,15 @@ public:
QString getObject(const QString& path);
void updateMilestonesComboData(int exitCode, QProcess::ExitStatus exitStatus);
void updateReleasesComboData(int exitCode, QProcess::ExitStatus exitStatus);
void updateSectionsComboData(int exitCode, QProcess::ExitStatus exitStatus);
void updateRunsComboData(int exitCode, QProcess::ExitStatus exitStatus);
void createTestRailRun(const QString& outputDirectory);
void updateTestRailRunResults(const QString& testResults, const QString& tempDirectory);
void addRun();
void updateRunWithResults();
bool setPythonCommand();
@ -94,6 +102,7 @@ private:
BusyWindow _busyWindow;
TestRailTestCasesSelectorWindow _testRailTestCasesSelectorWindow;
TestRailRunSelectorWindow _testRailRunSelectorWindow;
TestRailResultsSelectorWindow _testRailResultsSelectorWindow;
QString _url;
QString _user;
@ -109,11 +118,15 @@ private:
const QString pythonExe{ "python.exe" };
QString _pythonCommand;
std::map<QString, int> _milestones;
QStringList _milestoneNames;
QStringList _releaseNames;
std::map<QString, int> _sections;
QStringList _sectionNames;
std::vector<int> _sectionIDs;
QStringList _runNames;
std::vector<int> _runIDs;
QString tempName{ "fgadhcUDHSFaidsfh3478JJJFSDFIUSOEIrf" };
};
#endif

View file

@ -15,20 +15,24 @@
#include <shellapi.h>
#endif
AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) {
AutoTester::AutoTester(QWidget* parent) : QMainWindow(parent) {
_ui.setupUi(this);
_ui.checkBoxInteractiveMode->setChecked(true);
_ui.progressBar->setVisible(false);
_ui.tabWidget->setCurrentIndex(0);
_signalMapper = new QSignalMapper();
connect(_ui.actionClose, &QAction::triggered, this, &AutoTester::on_closeButton_clicked);
connect(_ui.actionAbout, &QAction::triggered, this, &AutoTester::about);
connect(_ui.actionContent, &QAction::triggered, this, &AutoTester::content);
#ifndef Q_OS_WIN
_ui.hideTaskbarButton->setVisible(false);
_ui.showTaskbarButton->setVisible(false);
_ui.tabWidget->setTabEnabled(3, false);
#endif
// helpWindow.textBrowser->setText()
}
void AutoTester::setup() {
@ -40,6 +44,16 @@ void AutoTester::runFromCommandLine(const QString& testFolder, const QString& br
_test->startTestsEvaluation(testFolder, branch, user);
}
void AutoTester::on_tabWidget_currentChanged(int index) {
if (index == 1 || index == 2) {
_ui.userTextEdit->setDisabled(false);
_ui.branchTextEdit->setDisabled(false);
} else {
_ui.userTextEdit->setDisabled(true);
_ui.branchTextEdit->setDisabled(true);
}
}
void AutoTester::on_evaluateTestsButton_clicked() {
_test->startTestsEvaluation();
}
@ -53,7 +67,7 @@ void AutoTester::on_createAllRecursiveScriptsButton_clicked() {
}
void AutoTester::on_createTestsButton_clicked() {
_test->createTests();
_test->createTests();
}
void AutoTester::on_createMDFileButton_clicked() {
@ -76,6 +90,10 @@ void AutoTester::on_createTestRailRunButton_clicked() {
_test->createTestRailRun();
}
void AutoTester::on_updateTestRailRunResultsButton_clicked() {
_test->updateTestRailRunResult();
}
// To toggle between show and hide
// if (uState & ABS_AUTOHIDE) on_showTaskbarButton_clicked();
// else on_hideTaskbarButton_clicked();
@ -114,7 +132,7 @@ void AutoTester::on_createXMLScriptRadioButton_clicked() {
void AutoTester::downloadImage(const QUrl& url) {
_downloaders.emplace_back(new Downloader(url, this));
connect(_downloaders[_index], SIGNAL (downloaded()), _signalMapper, SLOT (map()));
connect(_downloaders[_index], SIGNAL(downloaded()), _signalMapper, SLOT(map()));
_signalMapper->setMapping(_downloaders[_index], _index);
@ -140,7 +158,7 @@ void AutoTester::downloadImages(const QStringList& URLs, const QString& director
downloadImage(imageURL);
}
connect(_signalMapper, SIGNAL (mapped(int)), this, SLOT (saveImage(int)));
connect(_signalMapper, SIGNAL(mapped(int)), this, SLOT(saveImage(int)));
}
void AutoTester::saveImage(int index) {
@ -158,7 +176,7 @@ void AutoTester::saveImage(int index) {
++_numberOfImagesDownloaded;
if (_numberOfImagesDownloaded == _numberOfImagesToDownload) {
disconnect(_signalMapper, SIGNAL (mapped(int)), this, SLOT (saveImage(int)));
disconnect(_signalMapper, SIGNAL(mapped(int)), this, SLOT(saveImage(int)));
_test->finishTestsEvaluation(_isRunningFromCommandline, _ui.checkBoxInteractiveMode->isChecked(), _ui.progressBar);
} else {
_ui.progressBar->setValue(_numberOfImagesDownloaded);
@ -169,12 +187,15 @@ void AutoTester::about() {
QMessageBox::information(0, "About", QString("Built ") + __DATE__ + " : " + __TIME__);
}
void AutoTester::content() {
helpWindow.show();
}
void AutoTester::setUserText(const QString& user) {
_ui.userTextEdit->setText(user);
}
QString AutoTester::getSelectedUser()
{
QString AutoTester::getSelectedUser() {
return _ui.userTextEdit->toPlainText();
}

View file

@ -18,6 +18,8 @@
#include "../Downloader.h"
#include "../Test.h"
#include "HelpWindow.h"
class AutoTester : public QMainWindow {
Q_OBJECT
@ -38,15 +40,21 @@ public:
QString getSelectedBranch();
private slots:
void on_tabWidget_currentChanged(int index);
void on_evaluateTestsButton_clicked();
void on_createRecursiveScriptButton_clicked();
void on_createAllRecursiveScriptsButton_clicked();
void on_createTestsButton_clicked();
void on_createMDFileButton_clicked();
void on_createAllMDFilesButton_clicked();
void on_createTestsOutlineButton_clicked();
void on_createTestRailTestCasesButton_clicked();
void on_createTestRailRunButton_clicked();
void on_updateTestRailRunResultsButton_clicked();
void on_hideTaskbarButton_clicked();
void on_showTaskbarButton_clicked();
@ -59,6 +67,7 @@ private slots:
void saveImage(int index);
void about();
void content();
private:
Ui::AutoTesterClass _ui;
@ -78,6 +87,8 @@ private:
int _index { 0 };
bool _isRunningFromCommandline { false };
HelpWindow helpWindow;
};
#endif // hifi_AutoTester_h

View file

@ -6,10 +6,16 @@
<rect>
<x>0</x>
<y>0</y>
<width>645</width>
<height>814</height>
<width>432</width>
<height>734</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>AutoTester</string>
</property>
@ -17,9 +23,9 @@
<widget class="QPushButton" name="closeButton">
<property name="geometry">
<rect>
<x>380</x>
<y>620</y>
<width>101</width>
<x>166</x>
<y>610</y>
<width>100</width>
<height>40</height>
</rect>
</property>
@ -27,157 +33,258 @@
<string>Close</string>
</property>
</widget>
<widget class="QPushButton" name="createTestsButton">
<widget class="QTabWidget" name="tabWidget">
<property name="geometry">
<rect>
<x>20</x>
<y>30</y>
<width>220</width>
<height>40</height>
<x>12</x>
<y>140</y>
<width>408</width>
<height>461</height>
</rect>
</property>
<property name="text">
<string>Create Tests</string>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_1">
<attribute name="title">
<string>Create</string>
</attribute>
<widget class="QPushButton" name="createTestsButton">
<property name="geometry">
<rect>
<x>96</x>
<y>20</y>
<width>220</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create Tests</string>
</property>
</widget>
<widget class="QPushButton" name="createMDFileButton">
<property name="geometry">
<rect>
<x>96</x>
<y>100</y>
<width>220</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create MD file</string>
</property>
</widget>
<widget class="QPushButton" name="createAllMDFilesButton">
<property name="geometry">
<rect>
<x>96</x>
<y>150</y>
<width>220</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create all MD files</string>
</property>
</widget>
<widget class="QPushButton" name="createTestsOutlineButton">
<property name="geometry">
<rect>
<x>96</x>
<y>230</y>
<width>220</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create Tests Outline</string>
</property>
</widget>
<widget class="QPushButton" name="createRecursiveScriptButton">
<property name="geometry">
<rect>
<x>96</x>
<y>310</y>
<width>220</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create Recursive Script</string>
</property>
</widget>
<widget class="QPushButton" name="createAllRecursiveScriptsButton">
<property name="geometry">
<rect>
<x>96</x>
<y>360</y>
<width>220</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create all Recursive Scripts</string>
</property>
</widget>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Evaluate</string>
</attribute>
<widget class="QProgressBar" name="progressBar">
<property name="geometry">
<rect>
<x>90</x>
<y>100</y>
<width>255</width>
<height>23</height>
</rect>
</property>
<property name="value">
<number>24</number>
</property>
</widget>
<widget class="QCheckBox" name="checkBoxInteractiveMode">
<property name="geometry">
<rect>
<x>90</x>
<y>50</y>
<width>131</width>
<height>20</height>
</rect>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If unchecked, will not show results during evaluation&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Interactive Mode</string>
</property>
</widget>
<widget class="QPushButton" name="evaluateTestsButton">
<property name="geometry">
<rect>
<x>200</x>
<y>40</y>
<width>101</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Evaluate Test</string>
</property>
</widget>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>TestRail</string>
</attribute>
<widget class="QPushButton" name="updateTestRailRunResultsButton">
<property name="geometry">
<rect>
<x>180</x>
<y>160</y>
<width>161</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Update Run Results</string>
</property>
</widget>
<widget class="QRadioButton" name="createPythonScriptRadioButton">
<property name="geometry">
<rect>
<x>80</x>
<y>40</y>
<width>95</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>Python</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QPushButton" name="createTestRailRunButton">
<property name="geometry">
<rect>
<x>180</x>
<y>100</y>
<width>161</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create Run</string>
</property>
</widget>
<widget class="QPushButton" name="createTestRailTestCasesButton">
<property name="geometry">
<rect>
<x>180</x>
<y>40</y>
<width>161</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create Test Cases</string>
</property>
</widget>
<widget class="QRadioButton" name="createXMLScriptRadioButton">
<property name="geometry">
<rect>
<x>80</x>
<y>60</y>
<width>95</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>XML</string>
</property>
</widget>
</widget>
<widget class="QWidget" name="tab_4">
<attribute name="title">
<string>Windows</string>
</attribute>
<widget class="QPushButton" name="hideTaskbarButton">
<property name="geometry">
<rect>
<x>100</x>
<y>100</y>
<width>211</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Hide Windows Taskbar</string>
</property>
</widget>
<widget class="QPushButton" name="showTaskbarButton">
<property name="geometry">
<rect>
<x>100</x>
<y>170</y>
<width>211</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Show Windows Taskbar</string>
</property>
</widget>
</widget>
</widget>
<widget class="QPushButton" name="evaluateTestsButton">
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>430</x>
<y>490</y>
<width>101</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Evaluate Test</string>
</property>
</widget>
<widget class="QPushButton" name="createRecursiveScriptButton">
<property name="geometry">
<rect>
<x>330</x>
<y>340</y>
<width>220</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create Recursive Script</string>
</property>
</widget>
<widget class="QCheckBox" name="checkBoxInteractiveMode">
<property name="geometry">
<rect>
<x>320</x>
<y>500</y>
<width>131</width>
<height>20</height>
</rect>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If unchecked, will not show results during evaluation&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Interactive Mode</string>
</property>
</widget>
<widget class="QProgressBar" name="progressBar">
<property name="geometry">
<rect>
<x>320</x>
<y>550</y>
<width>255</width>
<height>23</height>
</rect>
</property>
<property name="value">
<number>24</number>
</property>
</widget>
<widget class="QPushButton" name="createAllRecursiveScriptsButton">
<property name="geometry">
<rect>
<x>330</x>
<y>400</y>
<width>220</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create all Recursive Scripts</string>
</property>
</widget>
<widget class="QPushButton" name="createMDFileButton">
<property name="geometry">
<rect>
<x>20</x>
<y>110</y>
<width>220</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create MD file</string>
</property>
</widget>
<widget class="QPushButton" name="createAllMDFilesButton">
<property name="geometry">
<rect>
<x>20</x>
<y>160</y>
<width>220</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create all MD files</string>
</property>
</widget>
<widget class="QPushButton" name="createTestsOutlineButton">
<property name="geometry">
<rect>
<x>20</x>
<y>250</y>
<width>220</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create Tests Outline</string>
</property>
</widget>
<widget class="QPushButton" name="showTaskbarButton">
<property name="geometry">
<rect>
<x>10</x>
<y>440</y>
<width>211</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Show Windows Taskbar</string>
</property>
</widget>
<widget class="QPushButton" name="hideTaskbarButton">
<property name="geometry">
<rect>
<x>10</x>
<y>390</y>
<width>211</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Hide Windows Taskbar</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>330</x>
<y>55</y>
<x>110</x>
<y>90</y>
<width>81</width>
<height>16</height>
</rect>
@ -191,11 +298,31 @@
<string>GitHub Branch</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<widget class="QTextEdit" name="branchTextEdit">
<property name="geometry">
<rect>
<x>330</x>
<y>15</y>
<x>200</x>
<y>85</y>
<width>140</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QTextEdit" name="userTextEdit">
<property name="geometry">
<rect>
<x>200</x>
<y>47</y>
<width>140</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_4">
<property name="geometry">
<rect>
<x>110</x>
<y>50</y>
<width>81</width>
<height>16</height>
</rect>
@ -209,88 +336,13 @@
<string>GitHub User</string>
</property>
</widget>
<widget class="QTextEdit" name="userTextEdit">
<property name="geometry">
<rect>
<x>420</x>
<y>12</y>
<width>140</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QTextEdit" name="branchTextEdit">
<property name="geometry">
<rect>
<x>420</x>
<y>50</y>
<width>140</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="createTestRailTestCasesButton">
<property name="geometry">
<rect>
<x>410</x>
<y>100</y>
<width>140</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create TestRail Test Cases</string>
</property>
</widget>
<widget class="QRadioButton" name="createPythonScriptRadioButton">
<property name="geometry">
<rect>
<x>310</x>
<y>100</y>
<width>95</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>Python</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QRadioButton" name="createXMLScriptRadioButton">
<property name="geometry">
<rect>
<x>310</x>
<y>120</y>
<width>95</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>XML</string>
</property>
</widget>
<widget class="QPushButton" name="createTestRailRunButton">
<property name="geometry">
<rect>
<x>410</x>
<y>180</y>
<width>140</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Create TestRail Run</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>645</width>
<width>432</width>
<height>21</height>
</rect>
</property>
@ -305,6 +357,7 @@
<string>Help</string>
</property>
<addaction name="actionAbout"/>
<addaction name="actionContent"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuHelp"/>
@ -328,6 +381,11 @@
<string>About</string>
</property>
</action>
<action name="actionContent">
<property name="text">
<string>Content</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>

View file

@ -9,10 +9,6 @@
//
#include "BusyWindow.h"
#include <QtCore/QFileInfo>
#include <cmath>
BusyWindow::BusyWindow(QWidget *parent) {
setupUi(this);
}

View file

@ -0,0 +1,14 @@
//
// HelpWindow.cpp
//
// Created by Nissim Hadar on 8 Aug 2017.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "HelpWindow.h"
HelpWindow::HelpWindow(QWidget *parent) {
setupUi(this);
}

View file

@ -0,0 +1,22 @@
//
// HelpWindow.h
//
// Created by Nissim Hadar on 8 Aug 2017.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_HelpWindow_h
#define hifi_HelpWindow_h
#include "ui_HelpWindow.h"
class HelpWindow : public QDialog, public Ui::HelpWindow {
Q_OBJECT
public:
HelpWindow(QWidget* parent = Q_NULLPTR);
};
#endif

View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>HelpWindow</class>
<widget class="QDialog" name="HelpWindow">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>696</width>
<height>546</height>
</rect>
</property>
<property name="windowTitle">
<string>AutoTester Help</string>
</property>
<widget class="QTextEdit" name="textEdit">
<property name="geometry">
<rect>
<x>50</x>
<y>50</y>
<width>581</width>
<height>381</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>300</x>
<y>460</y>
<width>93</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>Close</string>
</property>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,104 @@
//
// TestRailResultsSelectorWindow.cpp
//
// Created by Nissim Hadar on 2 Aug 2017.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "TestRailResultsSelectorWindow.h"
#include <QtCore/QFileInfo>
#include <cmath>
TestRailResultsSelectorWindow::TestRailResultsSelectorWindow(QWidget *parent) {
setupUi(this);
projectIDLineEdit->setValidator(new QIntValidator(1, 999, this));
}
void TestRailResultsSelectorWindow::reset() {
urlLineEdit->setDisabled(false);
userLineEdit->setDisabled(false);
passwordLineEdit->setDisabled(false);
projectIDLineEdit->setDisabled(false);
OKButton->setDisabled(true);
runsLabel->setDisabled(true);
runsComboBox->setDisabled(true);
}
void TestRailResultsSelectorWindow::on_acceptButton_clicked() {
urlLineEdit->setDisabled(true);
userLineEdit->setDisabled(true);
passwordLineEdit->setDisabled(true);
projectIDLineEdit->setDisabled(true);
OKButton->setDisabled(false);
runsLabel->setDisabled(false);
runsComboBox->setDisabled(false);
close();
}
void TestRailResultsSelectorWindow::on_OKButton_clicked() {
userCancelled = false;
close();
}
void TestRailResultsSelectorWindow::on_cancelButton_clicked() {
userCancelled = true;
close();
}
bool TestRailResultsSelectorWindow::getUserCancelled() {
return userCancelled;
}
void TestRailResultsSelectorWindow::setURL(const QString& user) {
urlLineEdit->setText(user);
}
QString TestRailResultsSelectorWindow::getURL() {
return urlLineEdit->text();
}
void TestRailResultsSelectorWindow::setUser(const QString& user) {
userLineEdit->setText(user);
}
QString TestRailResultsSelectorWindow::getUser() {
return userLineEdit->text();
}
QString TestRailResultsSelectorWindow::getPassword() {
return passwordLineEdit->text();
}
void TestRailResultsSelectorWindow::setProjectID(const int project) {
projectIDLineEdit->setText(QString::number(project));
}
int TestRailResultsSelectorWindow::getProjectID() {
return projectIDLineEdit->text().toInt();
}
void TestRailResultsSelectorWindow::setSuiteID(const int project) {
suiteIDLineEdit->setText(QString::number(project));
}
int TestRailResultsSelectorWindow::getSuiteID() {
return suiteIDLineEdit->text().toInt();
}
void TestRailResultsSelectorWindow::updateRunsComboBoxData(QStringList data) {
runsComboBox->insertItems(0, data);
}
int TestRailResultsSelectorWindow::getRunID() {
return runsComboBox->currentIndex();
}

View file

@ -0,0 +1,50 @@
//
// TestRailResultsSelectorWindow.h
//
// Created by Nissim Hadar on 2 Aug 2017.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_TestRailResultsSelectorWindow_h
#define hifi_TestRailResultsSelectorWindow_h
#include "ui_TestRailResultsSelectorWindow.h"
class TestRailResultsSelectorWindow : public QDialog, public Ui::TestRailResultsSelectorWindow {
Q_OBJECT
public:
TestRailResultsSelectorWindow(QWidget* parent = Q_NULLPTR);
void reset();
bool getUserCancelled();
void setURL(const QString& user);
QString getURL();
void setUser(const QString& user);
QString getUser();
QString getPassword();
void setProjectID(const int project);
int getProjectID();
void setSuiteID(const int project);
int getSuiteID();
bool userCancelled{ false };
void updateRunsComboBoxData(QStringList data);
int getRunID();
private slots:
void on_acceptButton_clicked();
void on_OKButton_clicked();
void on_cancelButton_clicked();
};
#endif

View file

@ -0,0 +1,280 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TestRailResultsSelectorWindow</class>
<widget class="QDialog" name="TestRailResultsSelectorWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>533</width>
<height>474</height>
</rect>
</property>
<property name="windowTitle">
<string>TestRail Test Case Selector Window</string>
</property>
<widget class="QLabel" name="errorLabel">
<property name="geometry">
<rect>
<x>30</x>
<y>850</y>
<width>500</width>
<height>28</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>similarity</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>70</x>
<y>125</y>
<width>121</width>
<height>20</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>TestRail Password</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>70</x>
<y>25</y>
<width>121</width>
<height>20</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>TestRail URL</string>
</property>
</widget>
<widget class="QPushButton" name="OKButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>120</x>
<y>420</y>
<width>93</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>OK</string>
</property>
</widget>
<widget class="QPushButton" name="cancelButton">
<property name="geometry">
<rect>
<x>280</x>
<y>420</y>
<width>93</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>Cancel</string>
</property>
</widget>
<widget class="QLineEdit" name="passwordLineEdit">
<property name="geometry">
<rect>
<x>200</x>
<y>120</y>
<width>231</width>
<height>24</height>
</rect>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>70</x>
<y>75</y>
<width>121</width>
<height>20</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>TestRail User</string>
</property>
</widget>
<widget class="QLineEdit" name="projectIDLineEdit">
<property name="geometry">
<rect>
<x>200</x>
<y>170</y>
<width>231</width>
<height>24</height>
</rect>
</property>
<property name="echoMode">
<enum>QLineEdit::Normal</enum>
</property>
</widget>
<widget class="QLabel" name="label_4">
<property name="geometry">
<rect>
<x>70</x>
<y>175</y>
<width>121</width>
<height>20</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>TestRail Project ID</string>
</property>
</widget>
<widget class="QPushButton" name="acceptButton">
<property name="geometry">
<rect>
<x>200</x>
<y>270</y>
<width>231</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>Accept</string>
</property>
</widget>
<widget class="QComboBox" name="runsComboBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>160</x>
<y>350</y>
<width>271</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="runsLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>80</x>
<y>350</y>
<width>71</width>
<height>20</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>TestRail Run</string>
</property>
</widget>
<widget class="QLineEdit" name="urlLineEdit">
<property name="geometry">
<rect>
<x>200</x>
<y>20</y>
<width>231</width>
<height>24</height>
</rect>
</property>
<property name="echoMode">
<enum>QLineEdit::Normal</enum>
</property>
</widget>
<widget class="QLineEdit" name="userLineEdit">
<property name="geometry">
<rect>
<x>200</x>
<y>70</y>
<width>231</width>
<height>24</height>
</rect>
</property>
<property name="echoMode">
<enum>QLineEdit::Normal</enum>
</property>
</widget>
<widget class="QLineEdit" name="suiteIDLineEdit">
<property name="geometry">
<rect>
<x>200</x>
<y>215</y>
<width>231</width>
<height>24</height>
</rect>
</property>
<property name="echoMode">
<enum>QLineEdit::Normal</enum>
</property>
</widget>
<widget class="QLabel" name="label_5">
<property name="geometry">
<rect>
<x>70</x>
<y>220</y>
<width>121</width>
<height>20</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>TestRail Suite ID</string>
</property>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<tabstops>
<tabstop>urlLineEdit</tabstop>
<tabstop>userLineEdit</tabstop>
<tabstop>passwordLineEdit</tabstop>
<tabstop>projectIDLineEdit</tabstop>
<tabstop>suiteIDLineEdit</tabstop>
<tabstop>acceptButton</tabstop>
<tabstop>runsComboBox</tabstop>
<tabstop>OKButton</tabstop>
<tabstop>cancelButton</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View file

@ -96,6 +96,5 @@ void TestRailRunSelectorWindow::updateSectionsComboBoxData(QStringList data) {
}
int TestRailRunSelectorWindow::getSectionID() {
return 0;
sectionsComboBox->currentIndex();
return sectionsComboBox->currentIndex();
}

View file

@ -27,7 +27,9 @@ void TestRailTestCasesSelectorWindow::reset() {
projectIDLineEdit->setDisabled(false);
OKButton->setDisabled(true);
milestonesComboBox->setDisabled(true);
releasesLabel->setDisabled(true);
releasesComboBox->setDisabled(true);
}
void TestRailTestCasesSelectorWindow::on_acceptButton_clicked() {
@ -37,7 +39,9 @@ void TestRailTestCasesSelectorWindow::on_acceptButton_clicked() {
projectIDLineEdit->setDisabled(true);
OKButton->setDisabled(false);
milestonesComboBox->setDisabled(false);
releasesLabel->setDisabled(false);
releasesComboBox->setDisabled(false);
close();
}
@ -91,10 +95,10 @@ int TestRailTestCasesSelectorWindow::getSuiteID() {
return suiteIDLineEdit->text().toInt();
}
void TestRailTestCasesSelectorWindow::updateMilestonesComboBoxData(QStringList data) {
milestonesComboBox->insertItems(0, data);
void TestRailTestCasesSelectorWindow::updateReleasesComboBoxData(QStringList data) {
releasesComboBox->insertItems(0, data);
}
int TestRailTestCasesSelectorWindow::getMilestoneID() {
return milestonesComboBox->currentIndex();
int TestRailTestCasesSelectorWindow::getReleaseID() {
return releasesComboBox->currentIndex();
}

View file

@ -38,8 +38,8 @@ public:
bool userCancelled{ false };
void updateMilestonesComboBoxData(QStringList data);
int getMilestoneID();
void updateReleasesComboBoxData(QStringList data);
int getReleaseID();
private slots:
void on_acceptButton_clicked();

View file

@ -171,7 +171,7 @@
<string>Accept</string>
</property>
</widget>
<widget class="QComboBox" name="milestonesComboBox">
<widget class="QComboBox" name="releasesComboBox">
<property name="enabled">
<bool>false</bool>
</property>
@ -184,15 +184,15 @@
</rect>
</property>
</widget>
<widget class="QLabel" name="milestoneLabel">
<widget class="QLabel" name="releasesLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>140</x>
<x>80</x>
<y>350</y>
<width>121</width>
<width>181</width>
<height>20</height>
</rect>
</property>
@ -202,7 +202,7 @@
</font>
</property>
<property name="text">
<string>TestRail Milestone</string>
<string>TestRail Added for Release</string>
</property>
</widget>
<widget class="QLineEdit" name="urlLineEdit">
@ -271,7 +271,7 @@
<tabstop>projectIDLineEdit</tabstop>
<tabstop>suiteIDLineEdit</tabstop>
<tabstop>acceptButton</tabstop>
<tabstop>milestonesComboBox</tabstop>
<tabstop>releasesComboBox</tabstop>
<tabstop>OKButton</tabstop>
<tabstop>cancelButton</tabstop>
</tabstops>