From d2dd9bdce7d1f48b790884b1ef1e5dc833fd1c5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rapha=C3=ABl=20Doursenaud?= <rdoursenaud@gpcsolutions.fr>
Date: Sat, 23 Jul 2016 13:33:04 +0200
Subject: [PATCH] New: Installation process functional test

---
 composer.json                                 |   3 +-
 test/phpunit/functional/InstallTest.php       | 210 ++++++++++++++++++
 test/phpunit/functional/README.md             |  77 +++++++
 .../functional/DolibarrInstallTest.php        |  33 ---
 4 files changed, 289 insertions(+), 34 deletions(-)
 create mode 100644 test/phpunit/functional/InstallTest.php
 create mode 100644 test/phpunit/functional/README.md
 delete mode 100644 test/phpunit/zenfusion/functional/DolibarrInstallTest.php

diff --git a/composer.json b/composer.json
index fb3109fbc40..87f9822f376 100644
--- a/composer.json
+++ b/composer.json
@@ -30,7 +30,8 @@
         "jakub-onderka/php-parallel-lint": "^0",
         "jakub-onderka/php-console-highlighter": "^0",
         "phpunit/phpunit": "^4",
-        "squizlabs/php_codesniffer": "^2"
+        "squizlabs/php_codesniffer": "^2",
+        "phpunit/phpunit-selenium": "^2"
     },
     "suggest": {
         "ext-mysqlnd": "To use with MySQL or MariaDB",
diff --git a/test/phpunit/functional/InstallTest.php b/test/phpunit/functional/InstallTest.php
new file mode 100644
index 00000000000..534d1d602c0
--- /dev/null
+++ b/test/phpunit/functional/InstallTest.php
@@ -0,0 +1,210 @@
+<?php
+
+/* Copyright (C) 2016  Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
+ *
+ * Install functional test using PHPUnit's Selenium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Class InstallTest
+ */
+class InstallTest extends PHPUnit_Extensions_Selenium2TestCase
+{
+	protected static $url = 'https://dev.dolibarr.org';
+	protected static $db_name = 'dolibarr_test';
+	protected static $db_host = 'localhost';
+	protected static $db_admin_user = 'root';
+	protected static $db_admin_pass = '';
+	protected static $db_user = 'dolibarr';
+	protected static $db_pass = 'dolibarr';
+	protected static $dol_admin_user = 'admin';
+	protected static $dol_admin_pass = 'admin';
+
+	public static $browsers = array(
+		array(
+			'browser' => 'chrome',
+			'browserName' => 'chrome',
+			'sessionStrategy' => 'shared',
+			'desiredCapabilities' => array()
+		)
+	);
+
+	public static function setUpBeforeClass()
+	{
+		// Make sure we backup and remove the configuration file to force new install.
+		@rename('htdocs/conf/conf.php', sys_get_temp_dir() . '/conf.php');
+
+		// Start without a database
+		self::dropTestDatabase();
+
+		// Run the tests in the same window
+		self::shareSession(true);
+	}
+
+	protected static function dropTestDatabase()
+	{
+		$mysqli = new mysqli(self::$db_host, self::$db_admin_user, self::$db_admin_pass);
+		$mysqli->query("DROP DATABASE " . self::$db_name);
+	}
+
+	public static function tearDownAfterClass()
+	{
+		// Remove the generated configuration and restore the backed up file.
+		@unlink('htdocs/conf/conf.php');
+		@rename(sys_get_temp_dir() . '/conf.php', 'htdocs/conf/conf.php');
+
+		// Cleanup test database
+		self::dropTestDatabase();
+	}
+
+	public function setUp()
+	{
+		// Populating the database can take quite long.
+		$this->setSeleniumServerRequestsTimeout(120000);
+		$this->setBrowserUrl(self::$url);
+	}
+
+	public function testInstallRedirect()
+	{
+		$this->url('/');
+		$this->assertContains('/install/index.php', $this->url());
+	}
+
+	public function testInstallPageTitle()
+	{
+		$this->assertContains('Dolibarr', $this->title());
+	}
+
+	public function testInstallProcess()
+	{
+		// FIXME: the button itself should have an ID
+		$this->byId('nextbutton')->byTag('input')->click();
+		$this->assertContains('/install/check.php', $this->url());
+	}
+
+	public function testCheckPage()
+	{
+		$unavailable_choices = $this->byId('navail_choices');
+		$show_hide_choices = $this->byId('AShowChoices')->byTag('a');
+		$this->assertFalse($unavailable_choices->displayed());
+		// FIXME: the link itself should have an ID
+		$show_hide_choices->click();
+		$this->assertTrue($unavailable_choices->displayed());
+		$show_hide_choices->click();
+		$this->assertFalse($unavailable_choices->displayed());
+		$this->byClassName('button')->click();
+		$this->assertContains('/install/fileconf.php', $this->url());
+	}
+
+	public function testForm()
+	{
+		$this->assertFalse($this->byClassName('hideroot')->displayed());
+		$this->assertTrue($this->byClassName('hidesqlite')->displayed());
+
+		// FIXME: This element should have an ID
+		$this->assertFalse($this->byName('main_force_https')->selected());
+		$this->byName('main_force_https')->click();
+
+		$this->assertEquals('dolibarr', $this->byId('db_name')->value());
+		$this->byId('db_name')->clear();
+		$this->byId('db_name')->value(self::$db_name);
+
+		$this->assertEquals('mysqli', $this->byId('db_type')->value());
+
+		// FIXME: This element should have an ID
+		$this->assertEquals('localhost', $this->byName('db_host')->value());
+
+		$this->assertEquals(3306, $this->byId('db_port')->value());
+
+		$this->assertEquals('llx_', $this->byId('db_prefix')->value());
+
+		$this->byId('db_create_database')->click();
+		$this->assertTrue($this->byClassName('hideroot')->displayed());
+		$this->byId('db_create_database')->click();
+		$this->assertFalse($this->byClassName('hideroot')->displayed());
+
+		$this->byId('db_user')->value(self::$db_user);
+
+		$this->byId('db_pass')->value(self::$db_pass);
+
+		$this->byId('db_create_user')->click();
+		$this->assertTrue($this->byClassName('hideroot')->displayed());
+		$this->byId('db_create_user')->click();
+		$this->assertFalse($this->byClassName('hideroot')->displayed());
+
+		$this->byId('db_create_database')->click();
+		$this->byId('db_create_user')->click();
+		$this->assertTrue($this->byClassName('hideroot')->displayed());
+
+		$this->byId('db_user_root')->value('root');
+		$this->byId('db_pass_root')->value('');
+	}
+
+	public function testFormSubmit()
+	{
+		$this->byName('forminstall')->submit();
+		$this->assertContains('/install/step1.php', $this->url());
+	}
+
+	public function testStep1()
+	{
+		$this->assertFalse($this->byId('pleasewait')->displayed());
+		$start = new DateTimeImmutable();
+		// FIXME: the button itself should have an ID
+		$this->byId('nextbutton')->byTag('input')->click();
+		$time = $start->diff(new DateTimeImmutable());
+		echo "\nPopulating the database took " . $time->format("%s seconds.\n");
+		$this->assertContains('/install/step2.php', $this->url());
+	}
+
+	public function testStep2()
+	{
+		$this->byName('forminstall')->submit();
+		$this->assertContains('/install/step4.php', $this->url());
+	}
+
+	// There is no step 3
+
+	public function testStep4()
+	{
+		// FIXME: should have an ID
+		$this->byName('login')->value(self::$dol_admin_user);
+		// FIXME: should have an ID
+		$this->byName('pass')->value('admin');
+		// FIXME: should have an ID
+		$this->byName('pass_verif')->value(self::$dol_admin_pass);
+		// FIXME: the button itself should have an ID
+		$this->byId('nextbutton')->byTag('input')->click();
+		$this->assertContains('/install/step5.php', $this->url());
+	}
+
+	public function testStep5()
+	{
+		// FIXME: this button should have an ID
+		$this->byTag('a')->click();
+		$this->assertContains('/admin/index.php', $this->url());
+	}
+
+	public function testFirstLogin()
+	{
+		$this->assertEquals('login', $this->byTag('form')->attribute('id'));
+		$this->assertEquals(self::$dol_admin_user, $this->byId('username')->value());
+		$this->byId('password')->value(self::$dol_admin_pass);
+		// FIXME: login button should have an ID
+		$this->byId('login')->submit();
+		$this->assertEquals('mainbody', $this->byTag('body')->attribute('id'));
+	}
+}
diff --git a/test/phpunit/functional/README.md b/test/phpunit/functional/README.md
new file mode 100644
index 00000000000..21380100605
--- /dev/null
+++ b/test/phpunit/functional/README.md
@@ -0,0 +1,77 @@
+Functional tests for Dolibarr
+=============================
+A.k.a. end-to-end or acceptance tests.
+
+Prerequisites
+-------------
+
+### Web server
+
+Any web server compatible with Dolibarr will do.
+
+For the full test, it should be configured for serving Dolibarr's htdocs directory at `https://dev.dolibarr.org` with SSL/TLS enabled.
+
+If you want to test at another address and/or without SSL/TLS, you will have to alter the test configuration.
+
+### Database server
+
+#### MySQL or MariaDB.
+
+Running on localhost with the root user without password.
+
+The database used for the test is `dolibarr_test`.
+
+**WARNING:**  
+This database will be dropped before and after the test.  
+Make sure you don't hold any valuable information in it!
+
+A user called `dolibarr` with a password `dolibarr` will be created as part of the test.
+
+You can alter the test configuration to use another host, users and/or database.
+
+#### Other
+
+Unsupported at the moment.  
+Patches welcome.
+
+### Browser automation
+
+#### Server
+
+[Selenium](http://www.seleniumhq.org/)
+
+#### Driver
+
+##### Firefox
+
+Unsupported at the moment.
+
+I can't get the new [marionette](https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/WebDriver) [webdriver](https://github.com/mozilla/geckodriver/releases) to work on my workstation.
+Patches welcome.
+
+##### Chrome
+[Google Chrome](https://www.google.com/chrome)
+[ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver)
+
+### Test runner
+We leverage PHPUnit's selenium integration to run the tests.
+
+You can install it using composer.
+```
+composer --dev require phpunit/phpunit-selenium
+```
+
+Configuration
+-------------
+
+There is only one test at the moment.  
+Edit the test file — the configuration values are declared at the top of the class.
+
+Usage
+-----
+
+Make sure your servers (web, database and browser automation) are started.
+
+Then from Dolibarr's root directory, run:
+
+```htdocs/includes/bin/phpunit test/phpunit/functional```
diff --git a/test/phpunit/zenfusion/functional/DolibarrInstallTest.php b/test/phpunit/zenfusion/functional/DolibarrInstallTest.php
deleted file mode 100644
index 5fcb37fdb63..00000000000
--- a/test/phpunit/zenfusion/functional/DolibarrInstallTest.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-
-class ZenFusionInstallTest extends PHPUnit_Extensions_Selenium2TestCase
-{
-	public function setUp()
-	{
-		$this->setHost('localhost');
-		$this->setPort(4444);
-		$this->setBrowserUrl('http://dev.zenfusion.fr');
-		$this->setBrowser('chrome');
-	}
-
-	public function setUpPage()
-	{
-		$this->url('/');
-	}
-
-	public function testInstallRedirect()
-	{
-		$this->assertContains('/install/index.php', $this->url());
-	}
-
-	public function testInstallPageTitle()
-	{
-		$this->assertContains('Dolibarr', $this->title());
-	}
-
-	public function testInstallProcess()
-	{
-		$this->byName('forminstall')->submit();
-		$this->assertContains('/install/check.php', $this->url());
-	}
-}
-- 
GitLab