Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>tags/v28.0.0beta1
@@ -1621,36 +1621,6 @@ trigger: | |||
- pull_request | |||
- push | |||
--- | |||
kind: pipeline | |||
name: acceptance-login | |||
steps: | |||
- name: submodules | |||
image: ghcr.io/nextcloud/continuous-integration-alpine-git:latest | |||
commands: | |||
- git submodule update --init | |||
- name: acceptance-login | |||
image: ghcr.io/nextcloud/continuous-integration-acceptance-php8.0:latest | |||
commands: | |||
- tests/acceptance/run-local.sh --timeout-multiplier 10 --nextcloud-server-domain acceptance-login --selenium-server selenium:4444 allow-git-repository-modifications features/login.feature | |||
services: | |||
- name: selenium | |||
image: ghcr.io/nextcloud/continuous-integration-selenium:3.141.59 | |||
environment: | |||
# Reduce default log level for Selenium server (INFO) as it is too | |||
# verbose. | |||
JAVA_OPTS: -Dselenium.LOGGER.level=WARNING | |||
trigger: | |||
branch: | |||
- master | |||
- stable* | |||
event: | |||
- pull_request | |||
- push | |||
--- | |||
kind: pipeline | |||
name: acceptance-users |
@@ -0,0 +1,146 @@ | |||
import type { User } from '@nextcloud/cypress' | |||
describe('Login', () => { | |||
let user: User | |||
let disabledUser: User | |||
after(() => cy.deleteUser(user)) | |||
before(() => { | |||
// disable brute force protection | |||
cy.runOccCommand('config:system:set auth.bruteforce.protection.enabled --value false --type bool') | |||
cy.createRandomUser().then(($user) => { | |||
user = $user | |||
}) | |||
cy.createRandomUser().then(($user) => { | |||
disabledUser = $user | |||
cy.runOccCommand(`user:disable '${disabledUser.userId}'`) | |||
}) | |||
}) | |||
beforeEach(() => { | |||
cy.logout() | |||
}) | |||
it('log in with valid user and password', () => { | |||
// Given I visit the Home page | |||
cy.visit('/') | |||
// I see the login page | |||
cy.get('form[name="login"]').should('be.visible') | |||
// I log in with a valid user | |||
cy.get('form[name="login"]').within(() => { | |||
cy.get('input[name="user"]').type(user.userId) | |||
cy.get('input[name="password"]').type(user.password) | |||
cy.contains('button[data-login-form-submit]', 'Log in').click() | |||
}) | |||
// see that the login is done | |||
cy.get('[data-login-form-submit]').if().should('not.contain', 'Logging in') | |||
// Then I see that the current page is the Files app | |||
cy.url().should('match', /apps\/dashboard(\/|$)/) | |||
}) | |||
it('try to log in with valid user and invalid password', () => { | |||
// Given I visit the Home page | |||
cy.visit('/') | |||
// I see the login page | |||
cy.get('form[name="login"]').should('be.visible') | |||
// I log in with a valid user but invalid password | |||
cy.get('form[name="login"]').within(() => { | |||
cy.get('input[name="user"]').type(user.userId) | |||
cy.get('input[name="password"]').type(`${user.password}--wrong`) | |||
cy.contains('button', 'Log in').click() | |||
}) | |||
// see that the login is done | |||
cy.get('[data-login-form-submit]').if().should('not.contain', 'Logging in') | |||
// Then I see that the current page is the Login page | |||
cy.url().should('match', /\/login/) | |||
// And I see that a wrong password message is shown | |||
cy.get('form[name="login"]').then(($el) => expect($el.text()).to.match(/Wrong.+password/i)) | |||
cy.get('input[name="password"]:invalid').should('exist') | |||
}) | |||
it('try to log in with valid user and invalid password', () => { | |||
// Given I visit the Home page | |||
cy.visit('/') | |||
// I see the login page | |||
cy.get('form[name="login"]').should('be.visible') | |||
// I log in with a valid user but invalid password | |||
cy.get('form[name="login"]').within(() => { | |||
cy.get('input[name="user"]').type(user.userId) | |||
cy.get('input[name="password"]').type(`${user.password}--wrong`) | |||
cy.contains('button', 'Log in').click() | |||
}) | |||
// see that the login is done | |||
cy.get('[data-login-form-submit]').if().should('not.contain', 'Logging in') | |||
// Then I see that the current page is the Login page | |||
cy.url().should('match', /\/login/) | |||
// And I see that a wrong password message is shown | |||
cy.get('form[name="login"]').then(($el) => expect($el.text()).to.match(/Wrong.+password/i).and.to.match(/Wrong.+username/)) | |||
cy.get('input[name="password"]:invalid').should('exist') | |||
}) | |||
it('try to log in with invalid user', () => { | |||
// Given I visit the Home page | |||
cy.visit('/') | |||
// I see the login page | |||
cy.get('form[name="login"]').should('be.visible') | |||
// I log in with an invalid user but valid password | |||
cy.get('form[name="login"]').within(() => { | |||
cy.get('input[name="user"]').type(`${user.userId}--wrong`) | |||
cy.get('input[name="password"]').type(user.password) | |||
cy.contains('button', 'Log in').click() | |||
}) | |||
// see that the login is done | |||
cy.get('[data-login-form-submit]').if().should('not.contain', 'Logging in') | |||
// Then I see that the current page is the Login page | |||
cy.url().should('match', /\/login/) | |||
// And I see that a wrong password message is shown | |||
cy.get('form[name="login"]').then(($el) => expect($el.text()).to.match(/Wrong.+password/i).and.to.match(/Wrong.+username/)) | |||
cy.get('input[name="password"]:invalid').should('exist') | |||
}) | |||
it('try to log in as disabled user', () => { | |||
// Given I visit the Home page | |||
cy.visit('/') | |||
// I see the login page | |||
cy.get('form[name="login"]').should('be.visible') | |||
// When I log in with user disabledUser and password | |||
cy.get('form[name="login"]').within(() => { | |||
cy.get('input[name="user"]').type(disabledUser.userId) | |||
cy.get('input[name="password"]').type(disabledUser.password) | |||
cy.contains('button', 'Log in').click() | |||
}) | |||
// see that the login is done | |||
cy.get('[data-login-form-submit]').if().should('not.contain', 'Logging in') | |||
// Then I see that the current page is the Login page | |||
cy.url().should('match', /\/login/) | |||
// And I see that the disabled user message is shown | |||
cy.get('form[name="login"]').then(($el) => expect($el.text()).to.match(/User.+disabled/i)) | |||
cy.get('input[name="password"]:invalid').should('exist') | |||
}) | |||
it('try to logout', () => { | |||
cy.login(user) | |||
// Given I visit the Home page | |||
cy.visit('/') | |||
// I see the dashboard | |||
cy.url().should('match', /apps\/dashboard(\/|$)/) | |||
// When click logout | |||
cy.get('#user-menu button').should('exist').click() | |||
cy.get('#logout a').should('contain.text', 'Log out').click() | |||
// Then I see that the current page is the Login page | |||
cy.url().should('match', /\/login/) | |||
}) | |||
}) |
@@ -17,7 +17,6 @@ default: | |||
- FileListContext | |||
- FilesAppContext | |||
- FilesAppSharingContext | |||
- LoginPageContext | |||
- NotificationsContext | |||
- PublicShareContext | |||
- SearchContext | |||
@@ -46,7 +45,6 @@ default: | |||
- FileListContext | |||
- FilesAppContext | |||
- FilesAppSharingContext | |||
- LoginPageContext | |||
- NotificationsContext | |||
- PublicShareContext | |||
- SearchContext |
@@ -1,149 +0,0 @@ | |||
<?php | |||
/** | |||
* | |||
* @copyright Copyright (c) 2017, Daniel Calviño Sánchez (danxuliu@gmail.com) | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
use Behat\Behat\Context\Context; | |||
use Behat\Behat\Hook\Scope\BeforeScenarioScope; | |||
use PHPUnit\Framework\Assert; | |||
class LoginPageContext implements Context, ActorAwareInterface { | |||
use ActorAware; | |||
/** | |||
* @var FeatureContext | |||
*/ | |||
private $featureContext; | |||
/** | |||
* @var FilesAppContext | |||
*/ | |||
private $filesAppContext; | |||
public static function userNameField(): Locator { | |||
return Locator::forThe()->field("user")-> | |||
describedAs("User name field in Login page"); | |||
} | |||
public static function passwordField(): Locator { | |||
return Locator::forThe()->field("password")-> | |||
describedAs("Password field in Login page"); | |||
} | |||
public static function loginButton(): Locator { | |||
return Locator::forThe()->css(".button-vue[type='submit']")-> | |||
describedAs("Login button in Login page"); | |||
} | |||
public static function wrongPasswordMessage(): Locator { | |||
return Locator::forThe()->xpath("//*[@class = 'input-field__helper-text-message input-field__helper-text-message--error' and normalize-space() = 'Wrong username or password.']")-> | |||
describedAs("Wrong password message in Login page"); | |||
} | |||
/** | |||
* @return Locator | |||
*/ | |||
public static function userDisabledMessage() { | |||
return Locator::forThe()->xpath("//*[@class = 'input-field__helper-text-message input-field__helper-text-message--error' and normalize-space() = 'User disabled']")-> | |||
describedAs('User disabled message on login page'); | |||
} | |||
/** | |||
* @When I log in with user :user and password :password | |||
*/ | |||
public function iLogInWithUserAndPassword(string $user, string $password): void { | |||
$this->actor->find(self::userNameField(), 10)->setValue($user); | |||
$this->actor->find(self::passwordField())->setValue($password); | |||
$this->actor->find(self::loginButton())->click(); | |||
} | |||
/** | |||
* @Then I see that the current page is the Login page | |||
*/ | |||
public function iSeeThatTheCurrentPageIsTheLoginPage() { | |||
Assert::assertStringStartsWith( | |||
$this->actor->locatePath("/login"), | |||
$this->actor->getSession()->getCurrentUrl()); | |||
} | |||
/** | |||
* @Then I see that a wrong password message is shown | |||
*/ | |||
public function iSeeThatAWrongPasswordMessageIsShown() { | |||
Assert::assertTrue( | |||
$this->actor->find(self::wrongPasswordMessage(), 10)->isVisible()); | |||
} | |||
/** | |||
* @Then I see that the disabled user message is shown | |||
*/ | |||
public function iSeeThatTheDisabledUserMessageIsShown() { | |||
Assert::assertTrue( | |||
$this->actor->find(self::userDisabledMessage(), 10)->isVisible()); | |||
} | |||
/** | |||
* @BeforeScenario | |||
*/ | |||
public function getOtherRequiredSiblingContexts(BeforeScenarioScope $scope) { | |||
$environment = $scope->getEnvironment(); | |||
$this->featureContext = $environment->getContext("FeatureContext"); | |||
$this->filesAppContext = $environment->getContext("FilesAppContext"); | |||
} | |||
/** | |||
* @Given I am logged in | |||
*/ | |||
public function iAmLoggedIn() { | |||
$this->featureContext->iVisitTheHomePage(); | |||
$this->iLogInWithUserAndPassword("user0", "123456acb"); | |||
$this->filesAppContext->iSeeThatTheCurrentPageIsTheFilesApp(); | |||
} | |||
/** | |||
* @Given I am logged in as :userName | |||
*/ | |||
public function iAmLoggedInAs($userName) { | |||
$this->featureContext->iVisitTheHomePage(); | |||
$this->iLogInWithUserAndPassword($userName, "123456acb"); | |||
$this->filesAppContext->iSeeThatTheCurrentPageIsTheFilesApp(); | |||
} | |||
/** | |||
* @Given I am logged in as the admin | |||
*/ | |||
public function iAmLoggedInAsTheAdmin() { | |||
$this->featureContext->iVisitTheHomePage(); | |||
$this->iLogInWithUserAndPassword("admin", "admin"); | |||
$this->filesAppContext->iSeeThatTheCurrentPageIsTheFilesApp(); | |||
} | |||
/** | |||
* @Given I can not log in with user :user and password :password | |||
*/ | |||
public function iCanNotLogInWithUserAndPassword($user, $password) { | |||
$this->featureContext->iVisitTheHomePage(); | |||
$this->iLogInWithUserAndPassword($user, $password); | |||
$this->iSeeThatTheCurrentPageIsTheLoginPage(); | |||
$this->iSeeThatAWrongPasswordMessageIsShown(); | |||
} | |||
} |
@@ -1,55 +0,0 @@ | |||
@apache | |||
Feature: login | |||
Scenario: log in with valid user and password | |||
Given I visit the Home page | |||
When I log in with user user0 and password 123456acb | |||
Then I see that the current page is the Files app | |||
Scenario: try to log in with valid user and invalid password | |||
Given I visit the Home page | |||
When I log in with user user0 and password 654321 | |||
Then I see that the current page is the Login page | |||
And I see that a wrong password message is shown | |||
# Scenario: log in with valid user and invalid password once fixed by admin | |||
# Given I act as John | |||
# And I can not log in with user user0 and password 654231 | |||
# When I act as Jane | |||
# And I am logged in as the admin | |||
# And I open the User settings | |||
# And I set the password for user0 to 654321 | |||
# And I act as John | |||
# And I log in with user user0 and password 654321 | |||
# Then I see that the current page is the Files app | |||
Scenario: try to log in with invalid user | |||
Given I visit the Home page | |||
When I log in with user unknownUser and password 123456acb | |||
Then I see that the current page is the Login page | |||
And I see that a wrong password message is shown | |||
Scenario: try to log in as disabled user | |||
Given I visit the Home page | |||
When I log in with user disabledUser and password 123456acb | |||
Then I see that the current page is the Login page | |||
And I see that the disabled user message is shown | |||
Scenario: log in with invalid user once fixed by admin | |||
Given I act as John | |||
And I can not log in with user unknownUser and password 123456acb | |||
When I act as Jane | |||
And I am logged in as the admin | |||
And I open the User settings | |||
And I click the New user button | |||
And I see that the new user form is shown | |||
And I create user unknownUser with password 123456acb | |||
# And I see that the list of users contains the user unknownUser | |||
And I act as John | |||
And I log in with user unknownUser and password 123456acb | |||
Then I see that the current page is the Files app | |||
Scenario: log out | |||
Given I am logged in | |||
When I log out | |||
Then I see that the current page is the Login page |