Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop

This commit is contained in:
Laurent Destailleur 2020-10-25 15:22:35 +01:00
commit 70082d17b4
21 changed files with 516 additions and 383 deletions

View File

@ -927,7 +927,7 @@ if ($rowid > 0) {
// Bank account // Bank account
print '<tr class="bankswitchclass"><td class="fieldrequired">'.$langs->trans("FinancialAccount").'</td><td>'; print '<tr class="bankswitchclass"><td class="fieldrequired">'.$langs->trans("FinancialAccount").'</td><td>';
$form->select_comptes(GETPOST('accountid'), 'accountid', 0, '', 1); $form->select_comptes(GETPOST('accountid'), 'accountid', 0, '', 2);
print "</td></tr>\n"; print "</td></tr>\n";
// Payment mode // Payment mode

View File

@ -370,7 +370,7 @@ if ($action == 'create')
{ {
print '<tr><td>'; print '<tr><td>';
print $form->editfieldkey('BankAccount', 'selectaccountid', '', $object, 0, 'string', '', 1).'</td><td>'; print $form->editfieldkey('BankAccount', 'selectaccountid', '', $object, 0, 'string', '', 1).'</td><td>';
$form->select_comptes($accountid, "accountid", 0, '', 1); // Affiche liste des comptes courant $form->select_comptes($accountid, "accountid", 0, '', 2); // Affiche liste des comptes courant
print '</td></tr>'; print '</td></tr>';
} }

View File

@ -178,7 +178,7 @@ if ($action == 'create')
if (!empty($conf->banque->enabled)) if (!empty($conf->banque->enabled))
{ {
print '<tr><td class="fieldrequired">'.$langs->trans("Account").'</td><td>'; print '<tr><td class="fieldrequired">'.$langs->trans("Account").'</td><td>';
$form->select_comptes($_POST["accountid"], "accountid", 0, "courant=1", 1); // Affiche liste des comptes courant $form->select_comptes($_POST["accountid"], "accountid", 0, "courant=1", 2); // Affiche liste des comptes courant
print '</td></tr>'; print '</td></tr>';
print '<tr><td class="fieldrequired">'.$langs->trans("PaymentMode").'</td><td>'; print '<tr><td class="fieldrequired">'.$langs->trans("PaymentMode").'</td><td>';

View File

@ -236,7 +236,7 @@ if ($action == 'create')
print '<tr>'; print '<tr>';
print '<td class="fieldrequired">'.$langs->trans('AccountToDebit').'</td>'; print '<td class="fieldrequired">'.$langs->trans('AccountToDebit').'</td>';
print '<td>'; print '<td>';
$form->select_comptes(isset($_POST["accountid"]) ? $_POST["accountid"] : $charge->accountid, "accountid", 0, '', 1); // Show opend bank account list $form->select_comptes(isset($_POST["accountid"]) ? $_POST["accountid"] : $charge->accountid, "accountid", 0, '', 2); // Show opend bank account list
print '</td></tr>'; print '</td></tr>';
// Number // Number

View File

@ -370,7 +370,7 @@ if ($action == 'create')
if (!empty($conf->banque->enabled)) if (!empty($conf->banque->enabled))
{ {
print '<tr><td>'.$langs->trans('BankAccount').'</td><td colspan="2">'; print '<tr><td>'.$langs->trans('BankAccount').'</td><td colspan="2">';
$form->select_comptes($fk_account, 'fk_account', 0, '', 1); $form->select_comptes($fk_account, 'fk_account', 0, '', 2);
print '</td></tr>'; print '</td></tr>';
} }

View File

@ -3901,7 +3901,7 @@ class Form
while ($i < $num) while ($i < $num)
{ {
$obj = $this->db->fetch_object($result); $obj = $this->db->fetch_object($result);
if ($selected == $obj->rowid) if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected)))
{ {
print '<option value="'.$obj->rowid.'" selected>'; print '<option value="'.$obj->rowid.'" selected>';
} else { } else {

View File

@ -215,7 +215,7 @@ if ($action == 'create')
print '<tr>'; print '<tr>';
print '<td class="fieldrequired">'.$langs->trans('AccountToCredit').'</td>'; print '<td class="fieldrequired">'.$langs->trans('AccountToCredit').'</td>';
print '<td colspan="2">'; print '<td colspan="2">';
$form->select_comptes(GETPOSTISSET("accountid") ? GETPOST("accountid") : $object->accountid, "accountid", 0, '', 1); // Show open bank account list $form->select_comptes(GETPOSTISSET("accountid") ? GETPOST("accountid") : $object->accountid, "accountid", 0, '', 2); // Show open bank account list
print '</td></tr>'; print '</td></tr>';
// Number // Number

View File

@ -262,7 +262,7 @@ if ($action == 'create' || empty($action))
print '<tr>'; print '<tr>';
print '<td class="fieldrequired">'.$langs->trans('AccountToDebit').'</td>'; print '<td class="fieldrequired">'.$langs->trans('AccountToDebit').'</td>';
print '<td colspan="2">'; print '<td colspan="2">';
$form->select_comptes(GETPOSTISSET("accountid") ? GETPOST("accountid", "int") : $expensereport->accountid, "accountid", 0, '', 1); // Show open bank account list $form->select_comptes(GETPOSTISSET("accountid") ? GETPOST("accountid", "int") : $expensereport->accountid, "accountid", 0, '', 2); // Show open bank account list
print '</td></tr>'; print '</td></tr>';
} }

View File

@ -60,8 +60,19 @@ Feature: Add user
Then the response status code should be "200" Then the response status code should be "200"
And user with login "<login>" should exist And user with login "<login>" should exist
Examples: Examples:
| last name | login | | last name | login |
| swi@ | s$5^2 | | swi@ | s$5^2 |
| g!!@%ui | | | g!!@%ui | |
| swikriti@h | ि $%#?&@name.txt | | swikriti@h | ि $%#?&@name.txt |
| !@#$%^&*()-_+ | España§àôœ€ | | !@#$%^&*()-_+ | España§àôœ€ |
Scenario: Non-admin user with api key adds user
Given the admin has created the following users
| login | last name | password | api_key |
| Harry | Potter | hello123 | harrypotter |
When the non-admin user "Harry" with password "hello123" creates user with following details using API
| last name | Potter |
| login | Ginny |
| password | password |
Then the response status code should be "200"
And user with login "Ginny" should exist

View File

@ -0,0 +1,23 @@
Feature: list users
As an admin user
I want to view the list of users
So that I can manage users
Scenario: Admin user should be able to see list of created users
Given the admin has created the following users
| login | last name | password |
| Harry | Potter | hello123 |
When the admin gets the list of all users using the API
Then the response status code should be "200"
And the user list returned by API should be following
| login | last name |
| dolibarr | SuperAdmin |
| Harry | Potter |
Scenario: Non-admin user should not be able to see list of created users
Given the admin has created the following users
| login | last name | password | api_key |
| Harry | Potter | hello123 | harrypotter |
When user "Harry" with password "hello123" tries to list all users using the API
Then the response status code should be "401"
And the error message should be "Unauthorized: You are not allowed to read list of users"

View File

@ -1,14 +1,14 @@
const { setDefaultTimeout, After, Before } = require('cucumber') const {setDefaultTimeout, After, Before} = require('cucumber')
const { createSession, closeSession, startWebDriver, stopWebDriver } = require('nightwatch-api') const {createSession, closeSession, startWebDriver, stopWebDriver} = require('nightwatch-api')
setDefaultTimeout(60000) setDefaultTimeout(60000)
Before(async () => { Before(async () => {
await startWebDriver(); await startWebDriver();
await createSession(); await createSession();
}) })
After(async () => { After(async () => {
await closeSession(); await closeSession();
await stopWebDriver(); await stopWebDriver();
}) })

View File

@ -1,128 +1,128 @@
const util = require('util'); const util = require('util');
module.exports = { module.exports = {
url: function () { url: function () {
return this.api.launchUrl + 'user/card.php?leftmenu=users&action=create'; return this.api.launchUrl + 'user/card.php?leftmenu=users&action=create';
}, },
commands: [ commands: [
{ {
adminCreatesUser: async function (dataTable) { adminCreatesUser: async function (dataTable) {
const userDetails = dataTable.rowsHash(); const userDetails = dataTable.rowsHash();
let administrator = userDetails['administrator']; let administrator = userDetails['administrator'];
let gender = userDetails['gender']; let gender = userDetails['gender'];
await this.waitForElementVisible('@newUserAddOption') await this.waitForElementVisible('@newUserAddOption')
.useXpath() .useXpath()
.waitForElementVisible('@lastnameField') .waitForElementVisible('@lastnameField')
.clearValue('@lastnameField') .clearValue('@lastnameField')
.setValue('@lastnameField', userDetails['last name']) .setValue('@lastnameField', userDetails['last name'])
.waitForElementVisible('@loginField') .waitForElementVisible('@loginField')
.clearValue('@loginField') .clearValue('@loginField')
.setValue('@loginField', userDetails['login']) .setValue('@loginField', userDetails['login'])
.waitForElementVisible('@newUserPasswordField') .waitForElementVisible('@newUserPasswordField')
.clearValue('@newUserPasswordField') .clearValue('@newUserPasswordField')
.setValue('@newUserPasswordField', userDetails['password']); .setValue('@newUserPasswordField', userDetails['password']);
if (userDetails['administrator']) { if (userDetails['administrator']) {
const admin = util.format(this.elements.administratorSelectOption.selector, administrator); const admin = util.format(this.elements.administratorSelectOption.selector, administrator);
await this.waitForElementVisible('@administratorField') await this.waitForElementVisible('@administratorField')
.click('@administratorField') .click('@administratorField')
.waitForElementVisible(admin) .waitForElementVisible(admin)
.click(admin); .click(admin);
} }
if (userDetails['gender']) { if (userDetails['gender']) {
const genderValue = util.format(this.elements.genderSelectOption.selector, gender) const genderValue = util.format(this.elements.genderSelectOption.selector, gender)
await this.waitForElementVisible('@genderField') await this.waitForElementVisible('@genderField')
.click('@genderField') .click('@genderField')
.waitForElementVisible(genderValue) .waitForElementVisible(genderValue)
.click(genderValue); .click(genderValue);
} }
return this.waitForElementVisible('@submitButton') return this.waitForElementVisible('@submitButton')
.click('@submitButton') .click('@submitButton')
.useCss(); .useCss();
}, },
noPermissionMessage: async function (message) { noPermissionMessage: async function (message) {
await this.useXpath() await this.useXpath()
.waitForElementVisible('@noPermissionDefinedMessage') .waitForElementVisible('@noPermissionDefinedMessage')
.expect.element('@noPermissionDefinedMessage') .expect.element('@noPermissionDefinedMessage')
.text.to.equal(message); .text.to.equal(message);
return this.useCss(); return this.useCss();
}, },
newUserShouldBeCreated: async function (lastname) { newUserShouldBeCreated: async function (lastname) {
await this.useXpath() await this.useXpath()
.waitForElementVisible('@newUserCreated') .waitForElementVisible('@newUserCreated')
.expect.element('@newUserCreated') .expect.element('@newUserCreated')
.text.to.equal(lastname); .text.to.equal(lastname);
return this.useCss(); return this.useCss();
}, },
noPermissionDefinedMessageNotShown: function (message) { noPermissionDefinedMessageNotShown: function (message) {
return this.useXpath() return this.useXpath()
.waitForElementNotPresent('@noPermissionDefinedMessage') .waitForElementNotPresent('@noPermissionDefinedMessage')
.useCss(); .useCss();
}, },
userNotCreated: function (lastname) { userNotCreated: function (lastname) {
return this.waitForElementVisible('@newUserAddOption'); return this.waitForElementVisible('@newUserAddOption');
} }
} }
], ],
elements: { elements: {
newUserAddOption: { newUserAddOption: {
selector: '.fiche' selector: '.fiche'
}, },
lastnameField: { lastnameField: {
selector: '//table[@class="border centpercent"]/tbody/tr/td//input[@id="lastname"]', selector: '//table[@class="border centpercent"]/tbody/tr/td//input[@id="lastname"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
loginField: { loginField: {
selector: '//table[@class="border centpercent"]/tbody/tr/td//input[@name="login"]', selector: '//table[@class="border centpercent"]/tbody/tr/td//input[@name="login"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
newUserPasswordField: { newUserPasswordField: {
selector: '//table[@class="border centpercent"]/tbody/tr/td//input[@name="password"]', selector: '//table[@class="border centpercent"]/tbody/tr/td//input[@name="password"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
submitButton: { submitButton: {
selector: '//div[@class="center"]/input[@class="button"]', selector: '//div[@class="center"]/input[@class="button"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
administratorField: { administratorField: {
selector: '//table[@class="border centpercent"]/tbody/tr/td//select[@id="admin"]', selector: '//table[@class="border centpercent"]/tbody/tr/td//select[@id="admin"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
administratorSelectOption: { administratorSelectOption: {
selector: '//select[@id="admin"]/option[.="%s"]', selector: '//select[@id="admin"]/option[.="%s"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
genderField: { genderField: {
selector: '//table[@class="border centpercent"]/tbody/tr/td//select[@id="gender"]', selector: '//table[@class="border centpercent"]/tbody/tr/td//select[@id="gender"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
genderSelectOption: { genderSelectOption: {
selector: '//select[@id="gender"]/option[.="%s"]', selector: '//select[@id="gender"]/option[.="%s"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
noPermissionDefinedMessage: { noPermissionDefinedMessage: {
selector: '//div[@class="jnotify-message"]', selector: '//div[@class="jnotify-message"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
newUserCreated: { newUserCreated: {
selector: '//div[contains(@class,"valignmiddle")]//div[contains(@class,"inline-block floatleft valignmiddle")]', selector: '//div[contains(@class,"valignmiddle")]//div[contains(@class,"inline-block floatleft valignmiddle")]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
} }
} }
}; };

View File

@ -1,44 +1,44 @@
module.exports = { module.exports = {
url: function () { url: function () {
return this.api.launchUrl + 'admin/index.php?mainmenu=home&leftmenu=setup&mesg=setupnotcomplete'; return this.api.launchUrl + 'admin/index.php?mainmenu=home&leftmenu=setup&mesg=setupnotcomplete';
}, },
commands: [ commands: [
{ {
browsedToNewUserPage: function () { browsedToNewUserPage: function () {
return this.useXpath() return this.useXpath()
.waitForElementVisible('@usersAndGroups') .waitForElementVisible('@usersAndGroups')
.click('@usersAndGroups') .click('@usersAndGroups')
.waitForElementVisible('@newUser') .waitForElementVisible('@newUser')
.click('@newUser') .click('@newUser')
.useCss(); .useCss();
}, },
browsedToListOfUsers: function () { browsedToListOfUsers: function () {
return this.useXpath() return this.useXpath()
.waitForElementVisible('@usersAndGroups') .waitForElementVisible('@usersAndGroups')
.click('@usersAndGroups') .click('@usersAndGroups')
.waitForElementVisible('@listOfUsers') .waitForElementVisible('@listOfUsers')
.click('@listOfUsers') .click('@listOfUsers')
.useCss(); .useCss();
} }
} }
], ],
elements: { elements: {
usersAndGroups: { usersAndGroups: {
selector: '//div[@class="menu_titre"]/a[@title="Users & Groups"]', selector: '//div[@class="menu_titre"]/a[@title="Users & Groups"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
newUser: { newUser: {
selector: '//div[@class="menu_contenu menu_contenu_user_card"]/a[@title="New user"]', selector: '//div[@class="menu_contenu menu_contenu_user_card"]/a[@title="New user"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
listOfUsers: { listOfUsers: {
selector: '//a[@class="vsmenu"][@title="List of users"]', selector: '//a[@class="vsmenu"][@title="List of users"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
} }
} }
}; };

View File

@ -1,47 +1,47 @@
const util = require('util'); const util = require('util');
module.exports = { module.exports = {
url: function () { url: function () {
return this.api.launchUrl + 'user/list.php?leftmenu=users'; return this.api.launchUrl + 'user/list.php?leftmenu=users';
}, },
commands: [ commands: [
{ {
listOfUsersDisplayed: async function (dataTable) { listOfUsersDisplayed: async function (dataTable) {
const usersList = dataTable.hashes(); const usersList = dataTable.hashes();
this.useXpath(); this.useXpath();
for (const row of usersList) { for (const row of usersList) {
let login = row['login']; let login = row['login'];
let lastName = row['last name']; let lastName = row['last name'];
const userDetail = util.format(this.elements.userList.selector, login, lastName); const userDetail = util.format(this.elements.userList.selector, login, lastName);
await this.waitForElementVisible('@userRow') await this.waitForElementVisible('@userRow')
.waitForElementVisible(userDetail); .waitForElementVisible(userDetail);
} }
return this.useCss(); return this.useCss();
}, },
numberOfUsersDisplayed: async function (number) { numberOfUsersDisplayed: async function (number) {
const userCount = util.format(this.elements.numberOfUsers.selector, number); const userCount = util.format(this.elements.numberOfUsers.selector, number);
await this.useXpath() await this.useXpath()
.waitForElementVisible(userCount); .waitForElementVisible(userCount);
return this.useCss(); return this.useCss();
} }
} }
], ],
elements: { elements: {
userRow: { userRow: {
selector: '//table[contains(@class,"tagtable")]/tbody/tr[position()>2]', selector: '//table[contains(@class,"tagtable")]/tbody/tr[position()>2]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
numberOfUsers: { numberOfUsers: {
selector: '//div[contains(@class, "titre inline-block") and contains(., "List of users")]/span[.="(%d)"]', selector: '//div[contains(@class, "titre inline-block") and contains(., "List of users")]/span[.="(%d)"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
userList: { userList: {
selector: '//table[contains(@class,"tagtable")]/tbody/tr[position()>2]/td/a//span[normalize-space(@class="nopadding usertext")][.="%s"]/../../following-sibling::td[.="%s"]', selector: '//table[contains(@class,"tagtable")]/tbody/tr[position()>2]/td/a//span[normalize-space(@class="nopadding usertext")][.="%s"]/../../following-sibling::td[.="%s"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
} }
} }
}; };

View File

@ -1,84 +1,84 @@
module.exports = { module.exports = {
url: function () { url: function () {
return this.api.launchUrl; return this.api.launchUrl;
}, },
commands: [ commands: [
{ {
waitForLoginPage: function () { waitForLoginPage: function () {
return this.waitForElementVisible('@loginTable'); return this.waitForElementVisible('@loginTable');
}, },
userLogsInWithUsernameAndPassword: function (username, password) { userLogsInWithUsernameAndPassword: function (username, password) {
return this.waitForElementVisible('@userNameField') return this.waitForElementVisible('@userNameField')
.setValue('@userNameField', username) .setValue('@userNameField', username)
.waitForElementVisible('@passwordField') .waitForElementVisible('@passwordField')
.setValue('@passwordField', password) .setValue('@passwordField', password)
.useXpath() .useXpath()
.waitForElementVisible('@loginButton') .waitForElementVisible('@loginButton')
.click('@loginButton') .click('@loginButton')
.useCss(); .useCss();
}, },
successfulLogin: function () { successfulLogin: function () {
return this.waitForElementNotPresent('@loginTable') return this.waitForElementNotPresent('@loginTable')
.waitForElementVisible('@userProfileDropdown'); .waitForElementVisible('@userProfileDropdown');
}, },
userIsLoggedIn: async function (login) { userIsLoggedIn: async function (login) {
await this.waitForElementNotPresent('@loginTable') await this.waitForElementNotPresent('@loginTable')
.useXpath() .useXpath()
.waitForElementVisible('@userLogin') .waitForElementVisible('@userLogin')
.expect.element('@userLogin') .expect.element('@userLogin')
.text.to.equal(login); .text.to.equal(login);
return this.useCss(); return this.useCss();
}, },
unsuccessfulLogin: function () { unsuccessfulLogin: function () {
return this.waitForElementVisible('@loginTable') return this.waitForElementVisible('@loginTable')
.waitForElementNotPresent('@userProfileDropdown'); .waitForElementNotPresent('@userProfileDropdown');
}, },
loginErrorDisplayed: async function (errorMessage) { loginErrorDisplayed: async function (errorMessage) {
await this.useXpath() await this.useXpath()
.waitForElementVisible('@loginError') .waitForElementVisible('@loginError')
.expect.element('@loginError') .expect.element('@loginError')
.text.to.equal(errorMessage); .text.to.equal(errorMessage);
return this.useCss(); return this.useCss();
} }
} }
], ],
elements: { elements: {
loginButton: { loginButton: {
selector: '//div[@id="login-submit-wrapper"]/input[@type="submit"]', selector: '//div[@id="login-submit-wrapper"]/input[@type="submit"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
userNameField: { userNameField: {
selector: '#username' selector: '#username'
}, },
passwordField: { passwordField: {
selector: '#password' selector: '#password'
}, },
loginTable: { loginTable: {
selector: '.login_table' selector: '.login_table'
}, },
userProfileDropdown: { userProfileDropdown: {
selector: '#topmenu-login-dropdown' selector: '#topmenu-login-dropdown'
}, },
userLogin: { userLogin: {
selector: '//div[@id="topmenu-login-dropdown"]/a//span[contains(@class,"atoploginusername")]', selector: '//div[@id="topmenu-login-dropdown"]/a//span[contains(@class,"atoploginusername")]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
}, },
loginError: { loginError: {
selector: '//div[@class="center login_main_message"]/div[@class="error"]', selector: '//div[@class="center login_main_message"]/div[@class="error"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
} }
} }
}; };

View File

@ -1,34 +1,34 @@
module.exports = { module.exports = {
url: function () { url: function () {
return this.api.launchUrl + 'admin/index.php?mainmenu=home&leftmenu=setup&mesg=setupnotcomplete'; return this.api.launchUrl + 'admin/index.php?mainmenu=home&leftmenu=setup&mesg=setupnotcomplete';
}, },
commands: commands:
[ [
{ {
userOpensProfile: async function () { userOpensProfile: async function () {
await this.useXpath() await this.useXpath()
.waitForElementVisible('@userProfileDropdown') .waitForElementVisible('@userProfileDropdown')
.click('@userProfileDropdown') .click('@userProfileDropdown')
return this.useCss(); return this.useCss();
}, },
userLogsOut: function () { userLogsOut: function () {
return this.waitForElementVisible('@logoutButton') return this.waitForElementVisible('@logoutButton')
.click('@logoutButton'); .click('@logoutButton');
} }
} }
], ],
elements: { elements: {
logoutButton: { logoutButton: {
selector: '.pull-right' selector: '.pull-right'
}, },
userProfileDropdown: { userProfileDropdown: {
selector: '//div[@id="topmenu-login-dropdown"]', selector: '//div[@id="topmenu-login-dropdown"]',
locateStrategy: 'xpath' locateStrategy: 'xpath'
} }
} }
}; };

View File

@ -1,13 +1,18 @@
const { Before, After } = require('cucumber'); const {Before, After} = require('cucumber');
const { client } = require('nightwatch-api'); const {client} = require('nightwatch-api');
const fetch = require('node-fetch'); const fetch = require('node-fetch');
let initialUsers = {}; let initialUsers = {};
let dolApiKey = ''; let dolApiKey = '';
const getUsers = async function () { const getUsers = async function (api_key = null) {
const header = {}; const header = {};
let dolApiKey;
const url = client.globals.backend_url + 'api/index.php/users'; const url = client.globals.backend_url + 'api/index.php/users';
const users = {}; if (api_key === null) {
dolApiKey = client.globals.dolApiKey;
} else {
dolApiKey = api_key;
}
header['Accept'] = 'application/json'; header['Accept'] = 'application/json';
header['DOLAPIKEY'] = dolApiKey; header['DOLAPIKEY'] = dolApiKey;
await fetch(url, { await fetch(url, {
@ -15,63 +20,80 @@ const getUsers = async function () {
headers: header headers: header
}) })
.then(async (response) => { .then(async (response) => {
const json_response = await response.json(); client.globals.response = response;
for (const user of json_response) {
users[user.id] = user.id;
}
}); });
};
const getUsersId = async function () {
const users = {};
await getUsers();
const json_response = await client.globals.response.json();
for (const user of json_response) {
users[user.id] = user.id;
}
return users; return users;
}; };
Before(async function getDolApiKey() { const getDolApiKey = async function (login = null, password = null) {
const header = {} const header = {};
const adminUsername = client.globals.adminUsername; if (login === null && password === null) {
const adminPassword = client.globals.adminPassword; login = client.globals.adminUsername;
const params = new URLSearchParams() password = client.globals.adminPassword;
params.set('login', adminUsername) }
params.set('password', adminPassword) const params = new URLSearchParams();
const apiKey = client.globals.backend_url + `api/index.php/login?${params.toString()}`; params.set('login', login);
header['Accept'] = 'application/json' params.set('password', password);
await fetch(apiKey, { const apiKey = client.globals.backend_url + `api/index.php/login?${params.toString()}`;
method: 'GET', header['Accept'] = 'application/json';
headers: header await fetch(apiKey, {
}) method: 'GET',
.then(async (response) => { headers: header
const jsonResponse = await response.json() })
dolApiKey = jsonResponse['success']['token'] .then(async (response) => {
client.globals.dolApiKey = dolApiKey const jsonResponse = await response.json();
}) dolApiKey = jsonResponse['success']['token'];
}) if (login === client.globals.adminUsername && password === client.globals.adminPassword) {
client.globals.dolApiKey = dolApiKey;
}
});
return dolApiKey;
};
Before(async function getAdminDolApiKey() {
await getDolApiKey();
});
Before(async () => { Before(async () => {
initialUsers = await getUsers(); initialUsers = await getUsersId();
}); });
After(async () => { After(async () => {
const finalUsers = await getUsers(); const finalUsers = await getUsersId();
const header = {}; const header = {};
const url = client.globals.backend_url + 'api/index.php/users/'; const url = client.globals.backend_url + 'api/index.php/users/';
header['Accept'] = 'application/json'; header['Accept'] = 'application/json';
header['DOLAPIKEY'] = dolApiKey; header['DOLAPIKEY'] = client.globals.dolApiKey;
let found; let found;
for (const finaluser in finalUsers) { for (const finaluser in finalUsers) {
for (const initialuser in initialUsers) { for (const initialuser in initialUsers) {
found = false; found = false;
if (initialuser === finaluser) { if (initialuser === finaluser) {
found = true; found = true;
break; break;
} }
} }
if (!found) { if (!found) {
await fetch(url + finaluser, { await fetch(url + finaluser, {
method: 'DELETE', method: 'DELETE',
headers: header headers: header
}) })
.then(res => { .then(res => {
if (res.status < 200 || res.status >= 400) { if (res.status < 200 || res.status >= 400) {
throw new Error("Failed to delete user: " + res.statusText); throw new Error("Failed to delete user: " + res.statusText);
} }
}); });
} }
} }
}); });
module.exports = {getDolApiKey, getUsers};

View File

@ -2,7 +2,7 @@ const {Given, When, Then} = require('cucumber');
const {client} = require('nightwatch-api'); const {client} = require('nightwatch-api');
const fetch = require('node-fetch'); const fetch = require('node-fetch');
const assert = require('assert'); const assert = require('assert');
let response; const {getDolApiKey} = require('../setup');
let Login = {}; let Login = {};
Given('the administrator has browsed to the new users page', function () { Given('the administrator has browsed to the new users page', function () {
@ -57,11 +57,20 @@ Then('the response message should be {string}', function (expectedResponseMessag
return getResponseMessage(expectedResponseMessage); return getResponseMessage(expectedResponseMessage);
}); });
const createUserRequest = function (login, lastname, password) { When('the non-admin user {string} with password {string} creates user with following details using API', async function (login, password, dataTable) {
const userDolApikey = await getDolApiKey(login, password);
return userCreatesUserWithApi(dataTable, userDolApikey);
});
const createUserRequest = function (login, lastname, password, api_key = null, dolApiKey = null) {
const header = {}; const header = {};
const url = client.globals.backend_url + 'api/index.php/users'; const url = client.globals.backend_url + 'api/index.php/users';
header['Accept'] = 'application/json'; header['Accept'] = 'application/json';
header['DOLAPIKEY'] = client.globals.dolApiKey; if (dolApiKey === null) {
header['DOLAPIKEY'] = client.globals.dolApiKey;
} else {
header['DOLAPIKEY'] = dolApiKey;
}
header['Content-Type'] = 'application/json'; header['Content-Type'] = 'application/json';
return fetch(url, { return fetch(url, {
method: 'POST', method: 'POST',
@ -70,7 +79,8 @@ const createUserRequest = function (login, lastname, password) {
{ {
login: login, login: login,
lastname: lastname, lastname: lastname,
pass: password pass: password,
api_key: api_key
} }
) )
}); });
@ -80,20 +90,39 @@ const adminCreatesUserWithAPI = function (dataTable) {
const userDetails = dataTable.rowsHash(); const userDetails = dataTable.rowsHash();
return createUserRequest(userDetails['login'], userDetails['last name'], userDetails['password']) return createUserRequest(userDetails['login'], userDetails['last name'], userDetails['password'])
.then((res) => { .then((res) => {
response = res; client.globals.response = res;
});
};
const userCreatesUserWithApi = function (dataTable, dolApiKey) {
const userDetails = dataTable.rowsHash();
return createUserRequest(userDetails['login'], userDetails['last name'], userDetails['password'], null, dolApiKey)
.then((res) => {
client.globals.response = res;
}); });
}; };
const adminHasCreatedUser = async function (dataTable) { const adminHasCreatedUser = async function (dataTable) {
const userDetails = dataTable.hashes(); const userDetails = dataTable.hashes();
for (const user of userDetails) { for (const user of userDetails) {
await createUserRequest(user['login'], user['last name'], user['password'])
.then((response) => { if (user['api_key']) {
if (response.status < 200 || response.status >= 400) { await createUserRequest(user['login'], user['last name'], user['password'], user['api_key'])
throw new Error('Failed to create user: ' + user['login'] + .then((response) => {
' ' + response.statusText); if (response.status < 200 || response.status >= 400) {
} throw new Error('Failed to create user: ' + user['login'] +
}); ' ' + response.statusText);
}
});
} else {
await createUserRequest(user['login'], user['last name'], user['password'])
.then((response) => {
if (response.status < 200 || response.status >= 400) {
throw new Error('Failed to create user: ' + user['login'] +
' ' + response.statusText);
}
});
}
} }
}; };
@ -137,13 +166,13 @@ const userShouldExist = async function (login) {
}; };
const getStatusCode = async function (expectedStatusCode) { const getStatusCode = async function (expectedStatusCode) {
const actualStatusCode = response.status.toString(); const actualStatusCode = client.globals.response.status.toString();
return assert.strictEqual(actualStatusCode, expectedStatusCode, return assert.strictEqual(actualStatusCode, expectedStatusCode,
`The expected status code was ${expectedStatusCode} but got ${actualStatusCode}`); `The expected status code was ${expectedStatusCode} but got ${actualStatusCode}`);
}; };
const getResponseMessage = async function (expectedResponseMessage) { const getResponseMessage = async function (expectedResponseMessage) {
const json_response = await response.json(); const json_response = await client.globals.response.json();
const actualResponseMessage = json_response['error']['0']; const actualResponseMessage = json_response['error']['0'];
return assert.strictEqual(actualResponseMessage, expectedResponseMessage, return assert.strictEqual(actualResponseMessage, expectedResponseMessage,
`the expected response message was ${expectedResponseMessage} but got ${actualResponseMessage}`); `the expected response message was ${expectedResponseMessage} but got ${actualResponseMessage}`);

View File

@ -1,14 +1,62 @@
const { When, Then } = require('cucumber'); const {When, Then} = require('cucumber');
const { client } = require('nightwatch-api'); const {client} = require('nightwatch-api');
const {getDolApiKey, getUsers} = require('../setup');
const assert = require('assert');
When('the administrator browses to the list of users page using the webUI', function () { When('the administrator browses to the list of users page using the webUI', function () {
return client.page.homePage().browsedToListOfUsers(); return client.page.homePage().browsedToListOfUsers();
}); });
Then('following users should be displayed in the users list', function (dataTable) { Then('following users should be displayed in the users list', function (dataTable) {
return client.page.listUsersPage().listOfUsersDisplayed(dataTable); return client.page.listUsersPage().listOfUsersDisplayed(dataTable);
}); });
Then('the number of created users should be {int}', function (number) { Then('the number of created users should be {int}', function (number) {
return client.page.listUsersPage().numberOfUsersDisplayed(number); return client.page.listUsersPage().numberOfUsersDisplayed(number);
}); });
When('the admin gets the list of all users using the API', function () {
return getUsers();
});
Then('the user list returned by API should be following', function (dataTable) {
return theUsersShouldBe(dataTable);
});
When('user {string} with password {string} tries to list all users using the API', async function (login, password) {
const userDolApikey = await getDolApiKey(login, password);
return getUsers(userDolApikey);
});
Then('the error message should be {string}', function (errorMessage) {
return getErrorMessage(errorMessage);
});
const theUsersShouldBe = async function (dataTable) {
const expectedUsers = dataTable.hashes();
let users = {};
const json_response = await client.globals.response.json();
for (const expectedUser of expectedUsers) {
let found;
for (const user of json_response) {
users["login"] = user.login;
users["last name"] = user.lastname;
found = false;
if (expectedUser["login"] === users.login && expectedUser["last name"] === users["last name"]) {
found = true;
break;
} else {
found = false;
}
}
assert.strictEqual(found, true);
}
};
const getErrorMessage = async function (expectedErrorMessage) {
const json_response = await client.globals.response.json();
const actualErrorMessage = json_response['error']['message'];
return assert.strictEqual(actualErrorMessage, expectedErrorMessage,
`the expected response message was ${expectedErrorMessage} but got ${actualErrorMessage}`);
};

View File

@ -1,5 +1,5 @@
const { Given, When, Then } = require('cucumber') const {Given, When, Then} = require('cucumber')
const { client } = require('nightwatch-api') const {client} = require('nightwatch-api')
Given('the administrator has logged in using the webUI', async function () { Given('the administrator has logged in using the webUI', async function () {
await client.page.loginPage().navigate().waitForLoginPage(); await client.page.loginPage().navigate().waitForLoginPage();
@ -8,21 +8,21 @@ Given('the administrator has logged in using the webUI', async function () {
}); });
Given('the user has browsed to the login page', function () { Given('the user has browsed to the login page', function () {
return client.page.loginPage().navigate(); return client.page.loginPage().navigate();
}); });
When('user logs in with username {string} and password {string}', function (username, password) { When('user logs in with username {string} and password {string}', function (username, password) {
return client.page.loginPage().userLogsInWithUsernameAndPassword(username, password); return client.page.loginPage().userLogsInWithUsernameAndPassword(username, password);
}); });
Then('the user should be directed to the homepage', function () { Then('the user should be directed to the homepage', function () {
return client.page.loginPage().successfulLogin(); return client.page.loginPage().successfulLogin();
}); });
Then('the user should not be able to login', function () { Then('the user should not be able to login', function () {
return client.page.loginPage().unsuccessfulLogin(); return client.page.loginPage().unsuccessfulLogin();
}); });
Then('error message {string} should be displayed in the webUI', function (errormessage) { Then('error message {string} should be displayed in the webUI', function (errormessage) {
return client.page.loginPage().loginErrorDisplayed(errormessage); return client.page.loginPage().loginErrorDisplayed(errormessage);
}); });

View File

@ -1,14 +1,14 @@
const { When, Then } = require('cucumber'); const {When, Then} = require('cucumber');
const { client } = require('nightwatch-api'); const {client} = require('nightwatch-api');
When('the user opens the user profile using the webUI', function () { When('the user opens the user profile using the webUI', function () {
return client.page.logoutPage().userOpensProfile(); return client.page.logoutPage().userOpensProfile();
}); });
When('the user logs out using the webUI', function () { When('the user logs out using the webUI', function () {
return client.page.logoutPage().userLogsOut(); return client.page.logoutPage().userLogsOut();
}); });
Then('the user should be logged out successfully', function () { Then('the user should be logged out successfully', function () {
return client.page.loginPage().waitForLoginPage(); return client.page.loginPage().waitForLoginPage();
}); });