diff --git a/docroot/modules/custom/va_gov_form_builder/css/va_gov_form_builder.css b/docroot/modules/custom/va_gov_form_builder/css/va_gov_form_builder.css
index 7c73c407f7..4cb8a821c1 100644
--- a/docroot/modules/custom/va_gov_form_builder/css/va_gov_form_builder.css
+++ b/docroot/modules/custom/va_gov_form_builder/css/va_gov_form_builder.css
@@ -6,6 +6,18 @@
font-family: var(--font-family-serif);
}
+/* links */
+.form-builder-page-container a {
+ text-decoration: underline;
+}
+
+.form-builder-page-container a:focus,
+.form-builder-page-container a:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+ color: var(--vads-color-base);
+ text-decoration: underline;
+}
+
/* headings */
.form-builder-page-container h1 {
font-size: var(--vads-font-size-heading-level-1);
@@ -56,3 +68,30 @@
line-height: var(--units-3);
padding: var(--units-1p5);
}
+
+/* buttons */
+.form-builder-button,
+a.form-builder-button {
+ border-radius: var(--units-0p5);
+ cursor: pointer;
+ font-weight: var(--font-weight-bold);
+ padding: var(--units-1p5) var(--units-2p5);
+ text-decoration: none;
+ transition: none;
+}
+
+.form-builder-button--primary,
+.form-builder-button--primary:focus,
+a.form-builder-button--primary,
+a.form-builder-button--primary:focus {
+ background: var(--vads-color-primary);
+ color: var(--vads-button-color-text-primary-on-light);
+ text-decoration: none;
+}
+
+.form-builder-button--primary:hover,
+a.form-builder-button--primary:hover {
+ background: var(--vads-color-primary-dark);
+ color: var(--vads-button-color-text-primary-on-light);
+ text-decoration: none;
+}
diff --git a/docroot/modules/custom/va_gov_form_builder/css/va_gov_form_builder__home.css b/docroot/modules/custom/va_gov_form_builder/css/va_gov_form_builder__home.css
new file mode 100644
index 0000000000..903acfd19b
--- /dev/null
+++ b/docroot/modules/custom/va_gov_form_builder/css/va_gov_form_builder__home.css
@@ -0,0 +1,30 @@
+/* Headings */
+.form-builder-page-content--home .form-builder-content-section__heading {
+ font-size: var(--vads-font-size-heading-level-4);
+}
+
+/* New form */
+.form-builder-content-section--new-form__subheading {
+ margin-bottom: var(--units-3);
+}
+
+/* Recent Forms */
+.form-builder-content-section--recent-forms {
+ margin-top: 60px;
+}
+
+.form-builder-content-section--recent-forms__forms-list {
+ border-top: var(--units-1px) solid var(--vads-color-base-light);
+ list-style-type: none;
+ margin: 0;
+ padding-bottom: var(--units-3);
+ padding-top: var(--units-1p5);
+}
+
+.form-builder-content-section--recent-forms__form-list-item {
+ margin-bottom: var(--units-1p5);
+}
+
+.form-builder-content-section--recent-forms__form-link {
+ font-weight: var(--font-weight-bold);
+}
diff --git a/docroot/modules/custom/va_gov_form_builder/src/Controller/VaGovFormBuilderController.php b/docroot/modules/custom/va_gov_form_builder/src/Controller/VaGovFormBuilderController.php
index 58709040ae..2ea5b9ff8a 100644
--- a/docroot/modules/custom/va_gov_form_builder/src/Controller/VaGovFormBuilderController.php
+++ b/docroot/modules/custom/va_gov_form_builder/src/Controller/VaGovFormBuilderController.php
@@ -3,6 +3,7 @@
namespace Drupal\va_gov_form_builder\Controller;
use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -24,6 +25,16 @@
*/
class VaGovFormBuilderController extends ControllerBase {
+ /**
+ * The prefix for the page-content theme definitions.
+ */
+ const PAGE_CONTENT_THEME_PREFIX = 'page_content__va_gov_form_builder__';
+
+ /**
+ * The prefix for the page-specific style libraries.
+ */
+ const LIBRARY_PREFIX = 'va_gov_form_builder/va_gov_form_builder_styles__';
+
/**
* The Drupal form builder.
*
@@ -32,11 +43,11 @@ class VaGovFormBuilderController extends ControllerBase {
private $drupalFormBuilder;
/**
- * The page subtitle.
+ * The Digital Forms service.
*
- * @var string
+ * @var \Drupal\va_gov_form_builder\Service\DigitalFormsService
*/
- private $subtitle;
+ private $digitalFormsService;
/**
* {@inheritdoc}
@@ -44,28 +55,29 @@ class VaGovFormBuilderController extends ControllerBase {
public static function create(ContainerInterface $container) {
$instance = parent::create($container);
$instance->drupalFormBuilder = $container->get('form_builder');
+ $instance->digitalFormsService = $container->get('va_gov_form_builder.digital_forms_service');
return $instance;
}
/**
- * Returns a render array representing the page with the passed-in form.
+ * Returns a render array representing the page with the passed-in content.
*
- * @param string $formName
- * The filename of the form to be rendered.
- * @param string $nid
- * The node id, passed in when the form in question edits an existing node.
+ * @param array $pageContent
+ * A render array representing the page content.
+ * @param string $subtitle
+ * The subtitle for the page.
+ * @param string $libraries
+ * Libraries for the page, in addition to the Form Builder general library,
+ * which is added automatically.
*/
- private function getFormPage($formName, $nid = NULL) {
- // @phpstan-ignore-next-line
- $form = $this->drupalFormBuilder->getForm('Drupal\va_gov_form_builder\Form\\' . $formName, $nid);
-
- return [
+ private function getPage($pageContent, $subtitle, $libraries = NULL) {
+ $page = [
'#type' => 'page',
- 'content' => $form,
+ 'content' => $pageContent,
// Add custom data.
'form_builder_page_data' => [
- 'subtitle' => $this->subtitle,
+ 'subtitle' => $subtitle,
],
// Add styles.
'#attached' => [
@@ -74,37 +86,86 @@ private function getFormPage($formName, $nid = NULL) {
],
],
];
+
+ if (!empty($libraries)) {
+ foreach ($libraries as $library) {
+ $page['#attached']['library'][] = self::LIBRARY_PREFIX . $library;
+ }
+ }
+
+ return $page;
}
/**
- * Entry point for the VA Form Builder. Redirects to the intro page.
+ * Returns a render array representing the page with the passed-in form.
+ *
+ * @param string $formName
+ * The filename of the form to be rendered.
+ * @param string $subtitle
+ * The subtitle for the page.
+ * @param string $libraries
+ * Libraries for the page, in addition to the Form Builder general library,
+ * which is added automatically.
+ * @param string $nid
+ * The node id, passed in when the form in question edits an existing node.
+ */
+ private function getFormPage($formName, $subtitle, $libraries = NULL, $nid = NULL) {
+ // @phpstan-ignore-next-line
+ $form = $this->drupalFormBuilder->getForm('Drupal\va_gov_form_builder\Form\\' . $formName, $nid);
+
+ return $this->getPage($form, $subtitle, $libraries);
+ }
+
+ /**
+ * Entry point for the VA Form Builder. Redirects to the home page.
*/
public function entry() {
- return $this->redirect('va_gov_form_builder.intro');
+ return $this->redirect('va_gov_form_builder.home');
}
/**
- * Intro page.
+ * Home page.
*/
- public function intro() {
- $this->subtitle = 'Subtitle Placeholder';
- return $this->getFormPage('Intro');
+ public function home() {
+ // Passing "FALSE" to fetch draft nodes rather than only published nodes.
+ $digitalForms = $this->digitalFormsService->getDigitalForms(FALSE);
+
+ $recentForms = [];
+ foreach ($digitalForms as $digitalForm) {
+ $recentForms[] = [
+ 'nid' => $digitalForm->id(),
+ 'title' => $digitalForm->getTitle(),
+ 'formNumber' => $digitalForm->get('field_va_form_number')->value,
+ ];
+ }
+
+ $pageContent = [
+ '#theme' => self::PAGE_CONTENT_THEME_PREFIX . 'home',
+ '#build_form_url' => Url::fromRoute('va_gov_form_builder.start_conversion')->toString(),
+ '#recent_forms' => $recentForms,
+ ];
+ $subtitle = 'Select a form';
+ $libraries = ['home'];
+
+ return $this->getPage($pageContent, $subtitle, $libraries);
}
/**
* Start-conversion page.
*/
public function startConversion() {
- $this->subtitle = 'Subtitle Placeholder';
- return $this->getFormPage('StartConversion');
+ $formName = 'StartConversion';
+ $subtitle = 'Subtitle Placeholder';
+ return $this->getFormPage($formName, $subtitle);
}
/**
* Name-and-date-of-birth page.
*/
public function nameAndDob($nid) {
- $this->subtitle = 'Subtitle Placeholder';
- return $this->getFormPage('NameAndDob', $nid);
+ $formName = 'NameAndDob';
+ $subtitle = 'Subtitle Placeholder';
+ return $this->getFormPage($formName, $subtitle, NULL, $nid);
}
}
diff --git a/docroot/modules/custom/va_gov_form_builder/src/Form/Intro.php b/docroot/modules/custom/va_gov_form_builder/src/Form/Intro.php
deleted file mode 100644
index 6ee3bc7f04..0000000000
--- a/docroot/modules/custom/va_gov_form_builder/src/Form/Intro.php
+++ /dev/null
@@ -1,103 +0,0 @@
- 'html_tag',
- '#tag' => 'h2',
- '#children' => $this->t('Working with the Form Builder'),
- ];
-
- $form['paragraph_1'] = [
- '#type' => 'html_tag',
- '#tag' => 'p',
- '#children' => $this->t('This is where the conversion of an existing form, or the continued editing
- of a converted form, takes place.'),
- ];
-
- $form['before_beginning_header'] = [
- '#type' => 'html_tag',
- '#tag' => 'h3',
- '#children' => $this->t('Before beginning'),
- ];
-
- $form['paragraph_2'] = [
- '#type' => 'html_tag',
- '#tag' => 'p',
- '#children' => $this->t('Make sure you have a copy of the form you are intending to convert.
- This will make it easier to reference the information
- that will be needed, and the order in which it appears for your users.'),
- ];
-
- $form['paragraph_3'] = [
- '#type' => 'html_tag',
- '#tag' => 'p',
- '#children' => $this->t('When returning to update an existing conversion, your past projects
- are listed under Projects at right.'),
- ];
-
- $form['paragraph_4'] = [
- '#type' => 'html_tag',
- '#tag' => 'p',
- '#children' => $this->t('If you need to access a conversion that you did not create, you can use the
- content search to find that project.'),
- ];
-
- $form['paragraph_5'] = [
- '#type' => 'html_tag',
- '#tag' => 'p',
- '#children' => $this->t('To begin a new project select Start conversion.'),
- ];
-
- $form['actions']['start_conversion'] = [
- '#type' => 'submit',
- '#value' => $this->t('Start conversion'),
- '#attributes' => [
- 'class' => [
- 'button',
- 'button--primary',
- 'js-form-submit',
- 'form-submit',
- ],
- ],
- ];
-
- return $form;
- }
-
- /**
- * {@inheritdoc}
- */
- public function submitForm(array &$form, FormStateInterface $form_state) {
- $form_state->setRedirect('va_gov_form_builder.start_conversion');
- }
-
-}
diff --git a/docroot/modules/custom/va_gov_form_builder/src/Form/StartConversion.php b/docroot/modules/custom/va_gov_form_builder/src/Form/StartConversion.php
index 51f6376f50..1c4ba0c1d4 100644
--- a/docroot/modules/custom/va_gov_form_builder/src/Form/StartConversion.php
+++ b/docroot/modules/custom/va_gov_form_builder/src/Form/StartConversion.php
@@ -133,7 +133,7 @@ protected function setDigitalFormNodeFromFormState(array &$form, FormStateInterf
* Submit handler for the 'Back' button.
*/
public function backButtonSubmitHandler(array &$form, FormStateInterface $form_state) {
- $form_state->setRedirect('va_gov_form_builder.intro');
+ $form_state->setRedirect('va_gov_form_builder.home');
}
/**
diff --git a/docroot/modules/custom/va_gov_form_builder/src/Service/DigitalFormsService.php b/docroot/modules/custom/va_gov_form_builder/src/Service/DigitalFormsService.php
new file mode 100644
index 0000000000..3b9a8ab4a6
--- /dev/null
+++ b/docroot/modules/custom/va_gov_form_builder/src/Service/DigitalFormsService.php
@@ -0,0 +1,54 @@
+entityTypeManager = $entityTypeManager;
+ }
+
+ /**
+ * Retrieves all Digital Form nodes.
+ *
+ * @param bool $publishedOnly
+ * Whether to retrieve only published nodes.
+ *
+ * @return \Drupal\node\NodeInterface[]
+ * An array of node objects of type 'digital_form'.
+ */
+ public function getDigitalForms($publishedOnly = TRUE) {
+ $query = $this->entityTypeManager->getStorage('node')->getQuery()
+ ->accessCheck(FALSE)
+ ->condition('type', 'digital_form');
+
+ if ($publishedOnly) {
+ $query->condition('status', 1);
+ }
+
+ $nids = $query->execute();
+
+ if (!empty($nids)) {
+ return $this->entityTypeManager->getStorage('node')->loadMultiple($nids);
+ }
+ return [];
+ }
+
+}
diff --git a/docroot/modules/custom/va_gov_form_builder/templates/page-content/page-content--va-gov-form-builder--home.html.twig b/docroot/modules/custom/va_gov_form_builder/templates/page-content/page-content--va-gov-form-builder--home.html.twig
new file mode 100644
index 0000000000..83702f0936
--- /dev/null
+++ b/docroot/modules/custom/va_gov_form_builder/templates/page-content/page-content--va-gov-form-builder--home.html.twig
@@ -0,0 +1,37 @@
+
+
Start a new form, or select a previous form to work with
+
+
+ Start a new form
+
+ Build a new form in Form Builder by selecting Build a form
+
+
+ Build a form
+
+
+
+
+ Recent forms
+ Select a recent form to edit
+
+
+
+
+
diff --git a/docroot/modules/custom/va_gov_form_builder/templates/page--va-gov-form-builder.html.twig b/docroot/modules/custom/va_gov_form_builder/templates/page/page--va-gov-form-builder.html.twig
similarity index 100%
rename from docroot/modules/custom/va_gov_form_builder/templates/page--va-gov-form-builder.html.twig
rename to docroot/modules/custom/va_gov_form_builder/templates/page/page--va-gov-form-builder.html.twig
diff --git a/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.libraries.yml b/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.libraries.yml
index 4c70ae555e..691f830b8f 100644
--- a/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.libraries.yml
+++ b/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.libraries.yml
@@ -5,3 +5,8 @@ va_gov_form_builder_styles:
css/va_gov_form_builder.css: {}
https://unpkg.com/@department-of-veterans-affairs/css-library@0.16.0/dist/tokens/css/variables.css:
{}
+va_gov_form_builder_styles__home:
+ version: 1.x
+ css:
+ theme:
+ css/va_gov_form_builder__home.css: {}
diff --git a/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.module b/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.module
index 69e564509f..cd4fce3e7f 100644
--- a/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.module
+++ b/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.module
@@ -21,13 +21,29 @@ function va_gov_form_builder_entity_bundle_field_info_alter(&$fields, EntityType
/**
* Implements hook_theme().
*/
-function va_gov_form_builder_theme() {
- return [
- 'page__va_gov_form_builder' => [
- 'base hook' => 'page',
- 'path' => \Drupal::service('extension.list.module')->getPath('va_gov_form_builder') . '/templates',
+function va_gov_form_builder_theme($_existing, $_type, $_theme, $path) {
+ $theme = [];
+
+ // Add page-wrapper theme.
+ $theme['page__va_gov_form_builder'] = [
+ 'base hook' => 'page',
+ 'path' => $path . '/templates/page',
+ ];
+
+ // Add page-content themes.
+ $page_content_theme_prefix = 'page_content__va_gov_form_builder__';
+ $page_content_theme_path = $path . '/templates/page-content';
+
+ // 1. Home page
+ $theme[$page_content_theme_prefix . 'home'] = [
+ 'path' => $page_content_theme_path,
+ 'variables' => [
+ 'recent_forms' => [],
+ 'build_form_url' => '',
],
];
+
+ return $theme;
}
/**
diff --git a/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.routing.yml b/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.routing.yml
index 52a9145505..1afecc33e9 100644
--- a/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.routing.yml
+++ b/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.routing.yml
@@ -2,10 +2,10 @@ va_gov_form_builder.entry:
path: "/form-builder"
defaults:
_controller: '\Drupal\va_gov_form_builder\Controller\VaGovFormBuilderController::entry'
-va_gov_form_builder.intro:
- path: "/form-builder/intro"
+va_gov_form_builder.home:
+ path: "/form-builder/home"
defaults:
- _controller: '\Drupal\va_gov_form_builder\Controller\VaGovFormBuilderController::intro'
+ _controller: '\Drupal\va_gov_form_builder\Controller\VaGovFormBuilderController::home'
va_gov_form_builder.start_conversion:
path: "/form-builder/start-conversion"
defaults:
diff --git a/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.services.yml b/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.services.yml
index b6af461fe8..507dbd20a9 100644
--- a/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.services.yml
+++ b/docroot/modules/custom/va_gov_form_builder/va_gov_form_builder.services.yml
@@ -3,3 +3,6 @@ services:
class: Drupal\va_gov_form_builder\Routing\RouteSubscriber
tags:
- { name: "event_subscriber" }
+ va_gov_form_builder.digital_forms_service:
+ class: Drupal\va_gov_form_builder\Service\DigitalFormsService
+ arguments: ["@entity_type.manager"]
diff --git a/tests/phpunit/va_gov_form_builder/Traits/TestFormLoads.php b/tests/phpunit/va_gov_form_builder/Traits/TestPageLoads.php
similarity index 69%
rename from tests/phpunit/va_gov_form_builder/Traits/TestFormLoads.php
rename to tests/phpunit/va_gov_form_builder/Traits/TestPageLoads.php
index 506f523ad3..1cd9a681e5 100644
--- a/tests/phpunit/va_gov_form_builder/Traits/TestFormLoads.php
+++ b/tests/phpunit/va_gov_form_builder/Traits/TestPageLoads.php
@@ -3,9 +3,9 @@
namespace tests\phpunit\va_gov_form_builder\Traits;
/**
- * Provides a trait for testing that forms load and do not load appropriately.
+ * Provides a trait for testing that pages load and do not load appropriately.
*/
-trait TestFormLoads {
+trait TestPageLoads {
/**
* Logs-in a user with appropriate privileges.
@@ -17,14 +17,14 @@ private function loginFormBuilderUser() {
}
/**
- * Test the form is accessible to a user with the correct privilege.
+ * Test the page is accessible to a user with the correct privilege.
*
* @param string $url
- * The (form) page to load.
+ * The page to load.
* @param string $expectedText
* The text expected to show on the loaded page.
*/
- private function sharedTestFormLoads($url, $expectedText) {
+ private function sharedTestPageLoads($url, $expectedText) {
// Log in a user with permission.
$this->loginFormBuilderUser();
@@ -36,12 +36,12 @@ private function sharedTestFormLoads($url, $expectedText) {
}
/**
- * Test the form is not accessible to a user without the correct privilege.
+ * Test the page is not accessible to a user without the correct privilege.
*
* @param string $url
- * The (form) page to load.
+ * The page to load.
*/
- private function sharedTestFormDoesNotLoad($url) {
+ private function sharedTestPageDoesNotLoad($url) {
// Log in a user without permission.
$this->drupalLogin($this->createUser([]));
diff --git a/tests/phpunit/va_gov_form_builder/functional/Controller/VaGovFormBuilderControllerTest.php b/tests/phpunit/va_gov_form_builder/functional/Controller/VaGovFormBuilderControllerTest.php
index 7c6bdae099..2eddf1cda5 100644
--- a/tests/phpunit/va_gov_form_builder/functional/Controller/VaGovFormBuilderControllerTest.php
+++ b/tests/phpunit/va_gov_form_builder/functional/Controller/VaGovFormBuilderControllerTest.php
@@ -4,6 +4,7 @@
use Drupal\Core\Url;
use Drupal\va_gov_form_builder\Controller\VaGovFormBuilderController;
+use Drupal\va_gov_form_builder\Service\DigitalFormsService;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Tests\Support\Classes\VaGovExistingSiteBase;
@@ -37,7 +38,15 @@ public function setUp(): void {
parent::setUp();
$container = new ContainerBuilder();
+
+ // Add Drupal's form builder to the service container.
$container->set('form_builder', \Drupal::formBuilder());
+
+ // Add our DigitalFormsService to the service container.
+ $digitalFormsService = new DigitalFormsService(\Drupal::service('entity_type.manager'));
+ $container->set('va_gov_form_builder.digital_forms_service', $digitalFormsService);
+
+ // Create the controller instance.
$this->controller = VaGovFormBuilderController::create($container);
}
@@ -45,7 +54,7 @@ public function setUp(): void {
* Tests css is included.
*/
public function testCssIncluded() {
- $page = $this->controller->intro();
+ $page = $this->controller->home();
$this->assertContains(
'va_gov_form_builder/va_gov_form_builder_styles',
@@ -61,17 +70,21 @@ public function testEntryRedirect() {
$response = $this->controller->entry();
$this->assertInstanceOf(RedirectResponse::class, $response);
- $this->assertStringContainsString(Url::fromRoute('va_gov_form_builder.intro')->toString(), $response->getTargetUrl());
+ $this->assertStringContainsString(Url::fromRoute('va_gov_form_builder.home')->toString(), $response->getTargetUrl());
}
/**
- * Tests the intro method returns an Intro form.
+ * Tests the home method returns a Home page.
*/
- public function testIntro() {
- $page = $this->controller->intro();
+ public function testHome() {
+ $page = $this->controller->home();
$this->assertArrayHasKey('content', $page);
- $this->assertArrayHasKey('working_with_form_builder_header', $page['content']);
+ $this->assertArrayHasKey('#theme', $page['content']);
+ $this->assertEquals('page_content__va_gov_form_builder__home', $page['content']['#theme']);
+
+ $this->assertArrayHasKey('#attached', $page);
+ $this->assertContains('va_gov_form_builder/va_gov_form_builder_styles__home', $page['#attached']['library']);
}
/**
diff --git a/tests/phpunit/va_gov_form_builder/functional/Form/IntroTest.php b/tests/phpunit/va_gov_form_builder/functional/Form/IntroTest.php
deleted file mode 100644
index 7c310d9aff..0000000000
--- a/tests/phpunit/va_gov_form_builder/functional/Form/IntroTest.php
+++ /dev/null
@@ -1,63 +0,0 @@
-loginFormBuilderUser();
- $this->drupalGet($this->getFormPageUrl());
- }
-
- /**
- * Test that the form is accessible to a user with the correct privilege.
- */
- public function testFormLoads() {
- $this->sharedTestFormLoads($this->getFormPageUrl(), 'Working with the Form Builder');
- }
-
- /**
- * Test that the form is not accessible to a user without privilege.
- */
- public function testFormDoesNotLoad() {
- $this->sharedTestFormDoesNotLoad($this->getFormPageUrl());
- }
-
- /**
- * Test the 'Start conversion' button.
- */
- public function testButton() {
- $this->click('.button#edit-start-conversion');
- $this->assertSession()->addressEquals('/form-builder/start-conversion');
- }
-
-}
diff --git a/tests/phpunit/va_gov_form_builder/functional/Form/NameAndDobTest.php b/tests/phpunit/va_gov_form_builder/functional/Form/NameAndDobTest.php
index 06a3d883ab..5134c98326 100644
--- a/tests/phpunit/va_gov_form_builder/functional/Form/NameAndDobTest.php
+++ b/tests/phpunit/va_gov_form_builder/functional/Form/NameAndDobTest.php
@@ -4,7 +4,7 @@
use Drupal\node\Entity\Node;
use tests\phpunit\va_gov_form_builder\Traits\SharedConstants;
-use tests\phpunit\va_gov_form_builder\Traits\TestFormLoads;
+use tests\phpunit\va_gov_form_builder\Traits\TestPageLoads;
use Tests\Support\Classes\VaGovExistingSiteBase;
/**
@@ -18,7 +18,7 @@
class NameAndDobTest extends VaGovExistingSiteBase {
use SharedConstants;
- use TestFormLoads;
+ use TestPageLoads;
/**
* {@inheritdoc}
@@ -65,17 +65,17 @@ public function setUp(): void {
}
/**
- * Test that the form is accessible to a user with the correct privilege.
+ * Test that the page is accessible to a user with the correct privilege.
*/
- public function testFormLoads() {
- $this->sharedTestFormLoads($this->getFormPageUrl(), 'Collecting Name and Date of birth');
+ public function testPageLoads() {
+ $this->sharedTestPageLoads($this->getFormPageUrl(), 'Collecting Name and Date of birth');
}
/**
- * Test that the form is not accessible to a user without privilege.
+ * Test that the page is not accessible to a user without privilege.
*/
- public function testFormDoesNotLoad() {
- $this->sharedTestFormDoesNotLoad($this->getFormPageUrl());
+ public function testPageDoesNotLoad() {
+ $this->sharedTestPageDoesNotLoad($this->getFormPageUrl());
}
/**
diff --git a/tests/phpunit/va_gov_form_builder/functional/Form/StartConversionTest.php b/tests/phpunit/va_gov_form_builder/functional/Form/StartConversionTest.php
index 597fa905fa..314ad6ea09 100644
--- a/tests/phpunit/va_gov_form_builder/functional/Form/StartConversionTest.php
+++ b/tests/phpunit/va_gov_form_builder/functional/Form/StartConversionTest.php
@@ -3,7 +3,7 @@
namespace tests\phpunit\va_gov_form_builder\functional\Form;
use tests\phpunit\va_gov_form_builder\Traits\SharedConstants;
-use tests\phpunit\va_gov_form_builder\Traits\TestFormLoads;
+use tests\phpunit\va_gov_form_builder\Traits\TestPageLoads;
use Tests\Support\Classes\VaGovExistingSiteBase;
/**
@@ -17,7 +17,7 @@
class StartConversionTest extends VaGovExistingSiteBase {
use SharedConstants;
- use TestFormLoads;
+ use TestPageLoads;
/**
* {@inheritdoc}
@@ -42,17 +42,17 @@ public function setUp(): void {
}
/**
- * Test that the form is accessible to a user with the correct privilege.
+ * Test that the page is accessible to a user with the correct privilege.
*/
- public function testFormLoads() {
- $this->sharedTestFormLoads($this->getFormPageUrl(), 'Start a new conversion');
+ public function testPageLoads() {
+ $this->sharedTestPageLoads($this->getFormPageUrl(), 'Start a new conversion');
}
/**
- * Test that the form is not accessible to a user without privilege.
+ * Test that the page is not accessible to a user without privilege.
*/
- public function testFormDoesNotLoad() {
- $this->sharedTestFormDoesNotLoad($this->getFormPageUrl());
+ public function testPageDoesNotLoad() {
+ $this->sharedTestPageDoesNotLoad($this->getFormPageUrl());
}
/**
@@ -95,11 +95,11 @@ public function testFormSubmissionFailsOnMissingRequiredField() {
}
/**
- * Test the 'Back' button takes the user back to the Intro page.
+ * Test the 'Back' button takes the user back to the Home page.
*/
public function testBackButton() {
$this->click('.button#edit-back');
- $this->assertSession()->addressEquals('/form-builder/intro');
+ $this->assertSession()->addressEquals('/form-builder/home');
}
}
diff --git a/tests/phpunit/va_gov_form_builder/functional/content-pages/HomeTest.php b/tests/phpunit/va_gov_form_builder/functional/content-pages/HomeTest.php
new file mode 100644
index 0000000000..5f00ef132a
--- /dev/null
+++ b/tests/phpunit/va_gov_form_builder/functional/content-pages/HomeTest.php
@@ -0,0 +1,87 @@
+loginFormBuilderUser();
+ }
+
+ /**
+ * Test that the page is accessible to a user with the correct privilege.
+ */
+ public function testPageLoads() {
+ $this->drupalGet($this->getPageUrl());
+ $this->sharedTestPageLoads($this->getPageUrl(), 'Start a new form, or select a previous form to work with');
+ }
+
+ /**
+ * Test that the page is not accessible to a user without privilege.
+ */
+ public function testPageDoesNotLoad() {
+ $this->drupalGet($this->getPageUrl());
+ $this->sharedTestPageDoesNotLoad($this->getPageUrl());
+ }
+
+ /**
+ * Test the 'Build a form' button.
+ */
+ public function testButton() {
+ $this->drupalGet($this->getPageUrl());
+ $this->click('a#form-builder-build-form-button');
+ $this->assertSession()->addressEquals('/form-builder/start-conversion');
+ }
+
+ /**
+ * Test the list of recent forms.
+ */
+ public function testRecentFormsList() {
+ $title = 'Test Digital Form ' . uniqid();
+ $formNumber = '99-9999';
+
+ // Create a new Digital Form node.
+ $this->createNode([
+ 'type' => 'digital_form',
+ 'title' => $title,
+ 'field_chapters' => [],
+ 'field_va_form_number' => $formNumber,
+ ]);
+
+ // Load page.
+ $this->drupalGet($this->getPageUrl());
+
+ // Ensure a link to the form appears on the page
+ // (in the list of recent forms).
+ // Ensure the link text is formatted as expected.
+ $this->assertSession()->linkExists($title . ' (VA Form ' . $formNumber . ')');
+ }
+
+}
diff --git a/tests/phpunit/va_gov_form_builder/functional/templates/FormBuilderPageTemplateTest.php b/tests/phpunit/va_gov_form_builder/functional/templates/FormBuilderPageTemplateTest.php
index 44c2395318..47c26834b6 100644
--- a/tests/phpunit/va_gov_form_builder/functional/templates/FormBuilderPageTemplateTest.php
+++ b/tests/phpunit/va_gov_form_builder/functional/templates/FormBuilderPageTemplateTest.php
@@ -11,7 +11,7 @@
* that should result in rendering a page that utilizes the
* page template under test. In this way, we can test the expected
* behavior of the template file in a consistent manner, assuming
- * the route properly utilizes the theme (which is tested elswhere).
+ * the route properly utilizes the theme (which is tested elsewhere).
*
* The route that makes the most sense here
* is the `entry` route, as that should always be present, regardless
diff --git a/tests/phpunit/va_gov_form_builder/unit/ModuleTest.php b/tests/phpunit/va_gov_form_builder/unit/ModuleTest.php
index 07ad0b2858..c2c296cdcd 100644
--- a/tests/phpunit/va_gov_form_builder/unit/ModuleTest.php
+++ b/tests/phpunit/va_gov_form_builder/unit/ModuleTest.php
@@ -3,7 +3,6 @@
namespace tests\phpunit\va_gov_form_builder\unit;
use Drupal\Core\DependencyInjection\ContainerBuilder;
-use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Routing\RouteMatchInterface;
use DrupalFinder\DrupalFinder;
use Tests\Support\Classes\VaGovUnitTestBase;
@@ -57,21 +56,29 @@ protected function setUp(): void {
* @covers ::va_gov_form_builder_theme
*/
public function testVaGovFormBuilderHookTheme() {
- // Mock the extension.list.module service and add to the container.
- $extensionListMock = $this->createMock(ModuleExtensionList::class);
- $extensionListMock->expects($this->once())
- ->method('getPath')
- ->with('va_gov_form_builder')
- ->willReturn($this->modulePath);
- $this->container->set('extension.list.module', $extensionListMock);
-
// Call the function to test.
- $result = va_gov_form_builder_theme();
+ $result = va_gov_form_builder_theme(
+ NULL,
+ NULL,
+ NULL,
+ $this->modulePath
+ );
// Assert the expected theme definition exists.
+ // Page (wrapper) theme.
$this->assertArrayHasKey('page__va_gov_form_builder', $result);
$this->assertEquals('page', $result['page__va_gov_form_builder']['base hook']);
- $this->assertEquals($this->modulePath . '/templates', $result['page__va_gov_form_builder']['path']);
+ $this->assertEquals($this->modulePath . '/templates/page', $result['page__va_gov_form_builder']['path']);
+
+ // Page-content themes.
+ $page_content_theme_prefix = 'page_content__va_gov_form_builder__';
+ $page_content_theme_path = $this->modulePath . '/templates/page-content';
+ // Home page.
+ $this->assertArrayHasKey($page_content_theme_prefix . 'home', $result);
+ $this->assertEquals($page_content_theme_path, $result[$page_content_theme_prefix . 'home']['path']);
+ $this->assertArrayHasKey('variables', $result[$page_content_theme_prefix . 'home']);
+ $this->assertArrayHasKey('recent_forms', $result[$page_content_theme_prefix . 'home']['variables']);
+ $this->assertArrayHasKey('build_form_url', $result[$page_content_theme_prefix . 'home']['variables']);
}
/**
diff --git a/tests/phpunit/va_gov_form_builder/unit/Service/DigitalFormsServiceTest.php b/tests/phpunit/va_gov_form_builder/unit/Service/DigitalFormsServiceTest.php
new file mode 100644
index 0000000000..ed937587c9
--- /dev/null
+++ b/tests/phpunit/va_gov_form_builder/unit/Service/DigitalFormsServiceTest.php
@@ -0,0 +1,195 @@
+entityTypeManager = $this->createMock(EntityTypeManagerInterface::class);
+
+ // Instantiate the service with the mocked dependencies.
+ $this->digitalFormsService = new DigitalFormsService($this->entityTypeManager);
+ }
+
+ /**
+ * Helper function to DRY up expectation setup.
+ */
+ private function setUpMockQuery($publishedOnly, $hasResults = TRUE) {
+ // Mock the entity storage.
+ $entityStorage = $this->createMock(EntityStorageInterface::class);
+
+ // Mock the query and return node IDs.
+ $query = $this->createMock(QueryInterface::class);
+
+ $query->method('accessCheck')
+ ->willReturnSelf();
+
+ if ($publishedOnly) {
+ $query->expects($this->exactly(2))
+ ->method('condition')
+ ->withConsecutive(
+ ['type', 'digital_form'],
+ ['status', 1],
+ )
+ ->willReturnSelf();
+ }
+ else {
+ $query->expects($this->once())
+ ->method('condition')
+ ->withConsecutive(
+ ['type', 'digital_form'],
+ )
+ ->willReturnSelf();
+ }
+
+ if ($hasResults) {
+ $query->expects($this->once())
+ ->method('execute')
+ ->willReturn([1, 2]);
+ }
+ else {
+ $query->expects($this->once())
+ ->method('execute')
+ ->willReturn(NULL);
+ }
+
+ // Mock the entity storage to return the query and nodes.
+ $entityStorage->expects($this->once())
+ ->method('getQuery')
+ ->willReturn($query);
+
+ if ($hasResults) {
+ $entityStorage->expects($this->once())
+ ->method('loadMultiple')
+ ->with([1, 2])
+ ->willReturn([
+ 1 => $this->createMock('Drupal\node\NodeInterface'),
+ 2 => $this->createMock('Drupal\node\NodeInterface'),
+ ]);
+ }
+
+ // Mock the entity type manager.
+ if ($hasResults) {
+ $this->entityTypeManager->expects($this->exactly(2))
+ ->method('getStorage')
+ ->with('node')
+ ->willReturn($entityStorage);
+ }
+ else {
+ $this->entityTypeManager->expects($this->once())
+ ->method('getStorage')
+ ->with('node')
+ ->willReturn($entityStorage);
+ }
+ }
+
+ /**
+ * Tests getDigitalForms() when $publishedOnly is TRUE.
+ *
+ * Query should include `status` condition.
+ *
+ * @covers ::getDigitalForms
+ */
+ public function testGetDigitalFormsPublishedOnlyTrue() {
+ // We will call the method with $publishedOnly = TRUE,
+ // so we set up expectations accordingly.
+ $this->setUpMockQuery(TRUE);
+
+ // Call the method, which asserts expectations set in setup.
+ $this->digitalFormsService->getDigitalForms(TRUE);
+ }
+
+ /**
+ * Tests getDigitalForms() when $publishedOnly is FALSE.
+ *
+ * Query should not include `status` condition.
+ *
+ * @covers ::getDigitalForms
+ */
+ public function testGetDigitalFormsPublishedOnlyFalse() {
+ // We will call the method with $publishedOnly = FALSE,
+ // so we set up expectations accordingly.
+ $this->setUpMockQuery(FALSE);
+
+ // Call the method, which asserts expectations set in setup.
+ $this->digitalFormsService->getDigitalForms(FALSE);
+ }
+
+ /**
+ * Tests getDigitalForms() defaults to $publishedOnly TRUE.
+ *
+ * @covers ::getDigitalForms
+ */
+ public function testGetDigitalFormsPublishedOnlyDefault() {
+ // We will call the method without passing $publishedOnly,
+ // and we want to ensure that the expectations are set up
+ // as though the value were set to TRUE, which is the
+ // expected default.
+ $this->setUpMockQuery(TRUE);
+
+ // Call the method, which asserts expectations set in setup.
+ $this->digitalFormsService->getDigitalForms();
+ }
+
+ /**
+ * Tests getDigitalForms() returns empty array if no results.
+ *
+ * @covers ::getDigitalForms
+ */
+ public function testGetDigitalFormsNoResults() {
+ // We set up the query to return no results
+ // by passing FALSE as second parameter.
+ //
+ // In the setup helper, this sets up expectations accordingly:
+ // 1. That
+ // `$this->entityTypeManager->getStorage('node')->loadMultiple($nids)`
+ // will not be called, since no node ids will be returned from
+ // the initial fetch.
+ //
+ // 2. That `$this->entityTypeManager->getStorage('node')`
+ // will be called only once, rather than twice,
+ // since there will be no need to call `loadMultiple`.
+ $this->setUpMockQuery(TRUE, FALSE);
+
+ // Call the method, which asserts expectations set in setup.
+ $result = $this->digitalFormsService->getDigitalForms(TRUE);
+
+ // Additionally, assert the function returns no results.
+ $this->assertCount(0, $result);
+ }
+
+}