refactor: replace custom CRM with Monica fork
Some checks failed
Build & Push Monica Image to Gitea Registry / build-and-push (push) Failing after 9s

This commit is contained in:
Kroonk
2026-05-22 16:19:55 +02:00
parent 38cc4c09ca
commit a213a1dba0
2215 changed files with 242567 additions and 6015 deletions

View File

@@ -0,0 +1,235 @@
<?php
namespace Tests\Browser\Auth;
use Tests\TestCase;
use GuzzleHttp\Client;
use App\Models\User\User;
use Tests\Traits\Asserts;
use Tests\Traits\ApiSignIn;
use Illuminate\Testing\TestResponse;
use Laravel\Passport\ClientRepository;
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
class AuthControllerTest extends TestCase
{
use ApiSignIn,
Asserts;
public function setUp(): void
{
parent::setUp();
if ($this->getActualConnection() != 'testing') {
$this->markTestSkipped("Set DB_CONNECTION on 'testing' to run this test.");
}
}
protected $jsonStructureOAuthLogin = [
'access_token',
'expires_in',
];
private const OAUTH_LOGIN_URL = 'http://localhost:8001/oauth/login';
public function test_oauth_login()
{
$repository = new ClientRepository();
$client = null;
try {
$client = $repository->createPasswordGrantClient(
null, config('app.name'), config('app.url')
);
$this->setEnvironmentValue([
'PASSPORT_PASSWORD_GRANT_CLIENT_ID' => $client->id,
'PASSPORT_PASSWORD_GRANT_CLIENT_SECRET' => $client->secret,
]);
$userPassword = 'password';
$user = factory(User::class)->create([
'password' => bcrypt($userPassword),
]);
$response = $this->postClient(self::OAUTH_LOGIN_URL, [
'email' => $user->email,
'password' => $userPassword,
]);
$response->assertStatus(200);
$response->assertJsonStructure($this->jsonStructureOAuthLogin);
} finally {
if ($client) {
$repository->delete($client);
}
if ($user) {
$user->account->delete();
}
}
}
public function test_oauth_login_bad_password()
{
$repository = new ClientRepository();
$client = null;
try {
$client = $repository->createPasswordGrantClient(
null, config('app.name'), config('app.url')
);
$this->setEnvironmentValue([
'PASSPORT_PASSWORD_GRANT_CLIENT_ID' => $client->id,
'PASSPORT_PASSWORD_GRANT_CLIENT_SECRET' => $client->secret,
]);
$userPassword = 'password';
$user = factory(User::class)->create([
'password' => bcrypt($userPassword),
]);
$response = $this->postClient(self::OAUTH_LOGIN_URL, [
'email' => $user->email,
'password' => 'wrongPassword',
]);
$this->expectNotAuthorized($response);
} finally {
if ($client) {
$repository->delete($client);
}
if ($user) {
$user->account->delete();
}
}
}
public function test_oauth_login_wrong_mail()
{
$response = $this->postClient(self::OAUTH_LOGIN_URL, [
'email' => 'badmail',
'password' => 'xx',
]);
$response->assertStatus(422);
$this->expectDataError($response, ['The email must be a valid email address.']);
}
public function test_oauth_login_wrong_password()
{
$response = $this->postClient(self::OAUTH_LOGIN_URL, [
'email' => 'mail@mail.com',
'password' => 'xx',
]);
$this->expectNotAuthorized($response);
}
public function test_oauth_login_2fa()
{
$repository = new ClientRepository();
$client = null;
try {
$client = $repository->createPasswordGrantClient(
null, config('app.name'), config('app.url')
);
$this->setEnvironmentValue([
'PASSPORT_PASSWORD_GRANT_CLIENT_ID' => $client->id,
'PASSPORT_PASSWORD_GRANT_CLIENT_SECRET' => $client->secret,
]);
$userPassword = 'password';
$user = factory(User::class)->create([
'password' => bcrypt($userPassword),
'google2fa_secret' => 'UFKZDTYO64WDEZPPQEO4HF3PC5UUTFLE',
]);
$response = $this->postClient(self::OAUTH_LOGIN_URL, [
'email' => $user->email,
'password' => $userPassword,
]);
$response->assertStatus(200);
$response->assertSee('Two Factor Authentication');
} finally {
if ($client) {
$repository->delete($client);
}
if ($user) {
$user->account->delete();
}
}
}
private function getActualConnection()
{
$handle = fopen('.env', 'r');
if (! $handle) {
return;
}
$value = null;
while (($line = fgets($handle)) !== false) {
if (preg_match('/DB_CONNECTION=(.{1,})/', $line, $matches)) {
$value = $matches[1];
break;
}
}
fclose($handle);
return $value;
}
private function setEnvironmentValue(array $values)
{
$envFile = app()->environmentFilePath();
$str = file_get_contents($envFile);
if (count($values) > 0) {
foreach ($values as $envKey => $envValue) {
$str .= "\n"; // In case the searched variable is in the last line without \n
$keyPosition = strpos($str, "{$envKey}=");
$endOfLinePosition = strpos($str, "\n", $keyPosition);
$oldLine = substr($str, $keyPosition, $endOfLinePosition - $keyPosition);
// If key does not exist, add it
if (! $keyPosition || ! $endOfLinePosition || ! $oldLine) {
$str .= "{$envKey}={$envValue}\n";
} else {
$str = str_replace($oldLine, "{$envKey}={$envValue}", $str);
}
}
}
$str = substr($str, 0, -1);
return file_put_contents($envFile, $str);
}
/**
* @param string $path
* @param array $param
* @return TestResponse
*/
protected function postClient($path, $param)
{
try {
$http = new Client([
'timeout' => 30,
]);
$response = $http->post($path, [
'form_params' => $param,
]);
} catch (\GuzzleHttp\Exception\RequestException $e) {
$response = $e->getResponse();
}
$factory = new HttpFoundationFactory();
$response = $factory->createResponse($response);
return TestResponse::fromBaseResponse($response);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Tests\Browser;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
/**
* A basic browser test example.
*
* @return void
*/
public function testBasicExample()
{
$this->browse(function ($browser) {
$browser->visit('/')
->assertSee('Login');
});
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace Tests\Browser\Feature;
use Tests\DuskTestCase;
use Tests\Browser\Pages\ImportVCardUpload;
class UploadVCardTest extends DuskTestCase
{
/**
* Make sure that the Add contact view has the link to the upload screen,
* and that the screen contains the blank view.
*
* @return void
*/
public function test_upload_vcard_is_accessible_from_add_contact_view()
{
$this->browse(function ($browser) {
$browser->login()
->visit('/people/add')
->assertSee('import your contacts');
$browser->clickLink('import your contacts')
->assertSee('You havent imported any contacts yet');
});
}
/**
* Make sure that the Import button leads to the Import screen, and that
* the cancel button leads to the Blank import screen.
*
* @return void
*/
public function test_import_button_leads_to_import_screen()
{
$this->browse(function ($browser) {
$browser->login()
->visit('/settings/import')
->clickLink('Import vCard')
->assertPathIs('/settings/import/upload')
->clickLink('Cancel')
->assertPathIs('/settings/import');
});
}
/**
* Upload a single contact from a valid vcard file.
*
* @return void
*/
public function test_user_can_import_contacts_from_a_vcf_card()
{
$this->browse(function ($browser) {
$browser->login()
->visit('/settings/import')
->clickLink('Import vCard')
->attach('vcard', base_path('tests/stubs/single_vcard_stub.vcard'))
->on(new ImportVCardUpload)
->scrollTo('upload')
->press('Upload')
->assertSee('1 imported');
});
}
/**
* Upload a contact from a broken vCard and see that it triggers an error.
*
* @return void
*/
public function test_user_see_error_when_importing_broken_vcard()
{
$this->browse(function ($browser) {
$browser->login()
->visit('/settings/import')
->clickLink('Import vCard')
->attach('vcard', base_path('tests/stubs/broken_vcard_stub.vcard'))
->on(new ImportVCardUpload)
->scrollTo('upload')
->press('Upload')
->assertSee('The vcard must be a file of type: vcf, vcard.');
});
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class DashboardValidate2fa extends Page
{
use DatabaseTransactions;
/**
* Get the URL for the page.
*
* @return string
*/
public function url()
{
return '/dashboard';
}
/**
* Assert that the browser is on the page.
*
* @param Browser $browser
* @return void
*/
public function assert(Browser $browser)
{
$browser->assertPathIs($this->url());
}
/**
* Get the element shortcuts for the page.
*
* @return array
*/
public function elements()
{
return [
'verify' => "button[name='verify']",
'otp' => '#one_time_password',
];
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class HomePage extends Page
{
use DatabaseTransactions;
/**
* Get the URL for the page.
*
* @return string
*/
public function url()
{
return '/';
}
/**
* Assert that the browser is on the page.
*
* @return void
*/
public function assert(Browser $browser)
{
//
}
/**
* Get the element shortcuts for the page.
*
* @return array
*/
public function elements()
{
return [
'@element' => '#selector',
];
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ImportVCardUpload extends Page
{
use DatabaseTransactions;
/**
* Get the URL for the page.
*
* @return string
*/
public function url()
{
return '/settings/import/upload';
}
/**
* Assert that the browser is on the page.
*
* @param Browser $browser
* @return void
*/
public function assert(Browser $browser)
{
$browser->assertPathIs($this->url());
}
/**
* Get the element shortcuts for the page.
*
* @return array
*/
public function elements()
{
return [
'upload' => '#upload',
];
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Page as BasePage;
abstract class Page extends BasePage
{
/**
* Get the global element shortcuts for the site.
*
* @return array
*/
public static function siteElements()
{
return [
'@link' => "a[@href='link']",
'alert' => '.alert',
];
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Tests\Browser\Pages\Settings;
use Laravel\Dusk\Browser;
use Tests\Browser\Pages\Page;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class SettingsPersonnalization extends Page
{
use DatabaseTransactions;
/**
* Get the URL for the page.
*
* @return string
*/
public function url()
{
return '/settings/personalization';
}
/**
* Assert that the browser is on the page.
*
* @param Browser $browser
* @return void
*/
public function assert(Browser $browser)
{
$browser->assertPathIs($this->url());
}
/**
* Get the element shortcuts for the page.
*
* @return array
*/
public function elements()
{
return [
'@reminder-rule-label' => '.reminder-rule-7 > span',
];
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class SettingsDAV extends Page
{
use DatabaseTransactions;
/**
* Get the URL for the page.
*
* @return string
*/
public function url()
{
return '/settings/dav';
}
/**
* Assert that the browser is on the page.
*
* @param Browser $browser
* @return void
*/
public function assert(Browser $browser)
{
$browser->assertPathIs($this->url());
}
/**
* Get the element shortcuts for the page.
*
* @return array
*/
public function elements()
{
return [
'dav_url_base' => '#dav_url_base',
];
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class SettingsSecurity extends Page
{
use DatabaseTransactions;
/**
* Get the URL for the page.
*
* @return string
*/
public function url()
{
return '/settings/security';
}
/**
* Assert that the browser is on the page.
*
* @param Browser $browser
* @return void
*/
public function assert(Browser $browser)
{
$browser->assertPathIs($this->url());
}
/**
* Get the element shortcuts for the page.
*
* @return array
*/
public function elements()
{
return [
'two_factor_link' => "a:contains('Enable Two Factor Authentication')",
'barcode' => '#barcode',
'secretkey' => '#secretkey',
'buttonVerify' => "button[name='verify']",
'enableVerify' => '#verify1',
'disableVerify' => '#verify2',
'otpenable' => '#one_time_password1',
'otpdisable' => '#one_time_password2',
'enableModal' => '#enableModal',
'disableModal' => '#disableModal',
'registerModal' => '#registerModal',
];
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class SettingsSecurity2faDisable extends Page
{
use DatabaseTransactions;
/**
* Get the URL for the page.
*
* @return string
*/
public function url()
{
return '/settings/security/2fa-disable';
}
/**
* Assert that the browser is on the page.
*
* @param Browser $browser
* @return void
*/
public function assert(Browser $browser)
{
$browser->assertPathIs($this->url());
}
/**
* Get the element shortcuts for the page.
*
* @return array
*/
public function elements()
{
return [
'verify' => "button[name='verify']",
'otp' => '#one_time_password',
];
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class SettingsSecurity2faEnable extends Page
{
use DatabaseTransactions;
/**
* Get the URL for the page.
*
* @return string
*/
public function url()
{
return '/settings/security/2fa-enable';
}
/**
* Assert that the browser is on the page.
*
* @param Browser $browser
* @return void
*/
public function assert(Browser $browser)
{
$browser->assertPathIs($this->url());
}
/**
* Get the element shortcuts for the page.
*
* @return array
*/
public function elements()
{
return [
'barcode' => '#barcode',
'secretkey' => '#secretkey',
'verify' => "button[name='verify']",
'otp' => '#one_time_password',
];
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class Validate2fa extends Page
{
use DatabaseTransactions;
/**
* Get the URL for the page.
*
* @return string
*/
public function url()
{
return '/validate2fa';
}
/**
* Assert that the browser is on the page.
*
* @param Browser $browser
* @return void
*/
public function assert(Browser $browser)
{
$browser->assertPathIs($this->url());
}
/**
* Get the element shortcuts for the page.
*
* @return array
*/
public function elements()
{
return [
'@element' => '#selector',
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Tests\Browser\Settings;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Tests\Browser\Pages\SettingsDAV;
class DAVControllerTest extends DuskTestCase
{
/**
* Test if the dav url is present.
*/
public function test_it_has_dav_url()
{
$this->browse(function (Browser $browser) {
$browser->login()
->visit(new SettingsDAV)
->assertVisible('dav_url_base')
->assertSourceHas(config('app.url').'/dav');
});
}
}

View File

@@ -0,0 +1,342 @@
<?php
namespace Tests\Browser\Settings;
use Zxing\QrReader;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Console\Application;
use Tests\Browser\Pages\SettingsSecurity;
use Tests\Browser\Pages\DashboardValidate2fa;
class MultiFAControllerTest extends DuskTestCase
{
/**
* Cleanup.
*/
public function cleanup()
{
exec(Application::formatCommandString('2fa:deactivate --force --email=admin@admin.com'), $output);
}
/**
* Test if the user has 2fa Enable Link in Security Page.
*
* @group multifa
*/
public function testHasSettings2faEnableLink()
{
$this->browse(function (Browser $browser) {
$browser->login()
->visit(new SettingsSecurity)
->assertSeeLink('Enable Two Factor Authentication');
});
}
/**
* Test if the user has WebAuthn Enable Link in Security Page.
*
* @group multifa
*/
public function testHasSettingsWebAuthnEnableLink()
{
$this->browse(function (Browser $browser) {
$browser->login()
->visit(new SettingsSecurity)
->assertSeeLink('Add a new security key');
});
}
/**
* Test the barcode generated in 2fa Enable Page.
*
* @group multifa
*/
public function testHas2faEnableBarCode()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal')
->assertVisible('barcode')
->assertVisible('secretkey');
});
}
/**
* Test the barcode generated in 2fa Enable Page.
*
* @group multifa
* @group multifabarcode
*/
public function testBarCodeContent()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser =
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal');
// \Facebook\WebDriver\Remote\RemoteWebElement
$barcode = $browser->element('barcode');
$imgsrc = $barcode->getAttribute('src');
$key = $this->unparseBarcode($imgsrc);
$this->assertEquals(32, strlen($key));
$this->assertEquals($browser->text('secretkey'), $key);
});
}
private function unparseBarcode($imgsrc)
{
$this->assertStringStartsWith('data:image/png', $imgsrc);
$imgcode = str_replace('data:image/png;base64,', '', $imgsrc);
$qrcode = new QrReader(base64_decode($imgcode), QrReader::SOURCE_TYPE_BLOB);
$text = $qrcode->text();
$this->assertStringStartsWith('otpauth://totp/', $text);
// unparse $text
// See PragmaRX\Google2FA\Support\QRCode getQRCodeUrl
// example :
//otpauth://totp/monicalocal.test:admin%40admin.com?secret=H25L7JLI7I57KYE7U53BIIOUELWXMRE6&issuer=monicalocal.test
$ret = preg_match('@^otpauth://totp/([^:]+):([^?]+)\?secret=([^&]+)&issuer=(.+)@i', $text, $matches);
$this->assertEquals(1, $ret, 'otp content does not match format');
$this->assertCount(5, $matches);
return $matches[3];
}
/**
* Test the 2fa Enable Page with wrong code.
*
* @group multifa
*/
public function testEnable2faWrongCode()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser =
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal')
->type('otpenable', '000000')
->scrollTo('enableVerify')
->press('enableVerify')
->waitUntilMissing('enableModal');
$this->assertTrue($this->hasNotification($browser));
$notification = $this->getNotification($browser);
$this->assertStringContainsString('error', $notification->getAttribute('class'));
$this->assertStringContainsString('Two Factor Authentication', $notification->getText());
});
}
/**
* Test the 2fa Enable Page.
*
* @group multifa
*/
public function testEnable2fa()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser =
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal');
$this->enable2fa($browser);
});
}
private function enable2fa(Browser $browser)
{
$secretkey = $browser->waitFor('enableModal')
->text('secretkey');
$google2fa = new \PragmaRX\Google2FA\Google2FA();
$one_time_password = $google2fa->getCurrentOtp($secretkey);
$browser->type('otpenable', $one_time_password);
$browser = $browser->scrollTo('enableVerify')
->press('enableVerify')
->waitUntilMissing('enableModal');
$this->assertTrue($this->hasNotification($browser));
$notification = $this->getNotification($browser);
$this->assertStringContainsString('success', $notification->getAttribute('class'));
$this->assertStringContainsString('Two Factor Authentication', $notification->getText());
// TODO: test if user has 2fa enabled actually
// TODO: test if session token auth is right
$browser->assertSeeLink('Disable Two Factor Authentication');
return $secretkey;
}
/**
* Test the 2fa Enable Page.
*
* @group multifa
*/
public function testEnable2faLoginWrongCode()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$user = call_user_func(Browser::$userResolver);
$this->browse(function (Browser $browser) use ($user) {
$browser =
$browser->loginAs($user)
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal');
$secretkey = $this->enable2fa($browser);
$browser =
$browser->clickLink('Logout')
->loginAs($user)
->visit(new DashboardValidate2fa)
->assertVisible('otp')
->type('otp', '000000')
->press('verify');
$this->assertTrue($this->hasDivAlert($browser));
$notification = $this->getDivAlert($browser);
$this->assertStringContainsString('alert-danger', $notification->getAttribute('class'));
$this->assertStringContainsString('The two factor authentication has failed.', $notification->getText());
});
}
/**
* Test the 2fa Enable Page.
*
* @group multifa
*/
public function testEnable2faLogin()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$user = call_user_func(Browser::$userResolver);
$this->browse(function (Browser $browser) use ($user) {
$browser =
$browser->loginAs($user)
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal');
$secretkey = $this->enable2fa($browser);
$google2fa = new \PragmaRX\Google2FA\Google2FA();
$one_time_password = $google2fa->getCurrentOtp($secretkey);
$browser =
$browser->clickLink('Logout')
->loginAs($user)
->visit(new DashboardValidate2fa)
->assertVisible('otp')
->type('otp', $one_time_password)
->press('verify');
$this->assertFalse($this->hasDivAlert($browser));
$browser->assertPathIs('/dashboard');
});
}
/**
* Test 2fa Enable Page and Disable Page.
*
* @group multifa
*/
public function testEnable2faDisable2fa()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser =
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal');
$secretkey = $this->enable2fa($browser);
$google2fa = new \PragmaRX\Google2FA\Google2FA();
$one_time_password = $google2fa->getCurrentOtp($secretkey);
$browser =
$browser->clickLink('Disable Two Factor Authentication')
->waitFor('disableModal')
->assertVisible('otpdisable')
->type('otpdisable', $one_time_password)
->scrollTo('disableVerify')
->press('disableVerify')
->waitUntilMissing('enableModal');
$this->assertTrue($this->hasNotification($browser));
$notification = $this->getNotification($browser);
$this->assertStringContainsString('success', $notification->getAttribute('class'));
$this->assertStringContainsString('Two Factor Authentication', $notification->getText());
});
}
/**
* Test 2fa Enable Page and Disable Page.
*
* @group multifa
*/
public function testEnable2faDisable2faWrongCode()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser =
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal');
$this->enable2fa($browser);
$browser =
$browser->clickLink('Disable Two Factor Authentication')
->waitFor('disableModal')
->assertVisible('otpdisable')
->type('otpdisable', '000000')
->scrollTo('disableVerify')
->press('disableVerify')
->waitUntilMissing('disableModal');
$this->assertTrue($this->hasNotification($browser));
$res = $browser->elements('.notification');
$notification = $res[1];
$this->assertStringContainsString('error', $notification->getAttribute('class'));
$this->assertStringContainsString('Two Factor Authentication', $notification->getText());
});
}
}

2
tests/Browser/console/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*
!.gitignore

2
tests/Browser/screenshots/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*
!.gitignore