IndexControllerTest.php #1

  • //
  • guest/
  • perforce_software/
  • chronicle/
  • main/
  • application/
  • workflow/
  • tests/
  • IndexControllerTest.php
  • View
  • Commits
  • Open Download .zip Download (23 KB)
<?php
/**
 * Test the workflow index controller.
 *
 * @copyright   2011 Perforce Software. All rights reserved.
 * @license     Please see LICENSE.txt in top-level folder of this distribution.
 * @version     <release>/<patch>
 */
class Workflow_Test_IndexControllerTest extends ModuleControllerTest
{
    /**
     * Test manage workflows grid.
     */
    public function testIndexAction()
    {
        $this->utility->impersonate('editor');

        // verify that workflows grid is accessible
        $this->dispatch('/workflow');

        $this->assertModule('workflow', 'Expected module for dispatching /workflow action.');
        $this->assertController('index', 'Expected controller for dispatching /workflow action.');
        $this->assertAction('index', 'Expected action for dispatching /workflow action.');

        // verify that table and dojo data elements exist
        $this->assertXpath('//div[@dojotype="dojox.data.QueryReadStore"]', 'Expected dojo.data div');
        $this->assertXpath(
            '//table[@dojotype="p4cms.ui.grid.DataGrid" and @jsid="p4cms.workflow.grid.instance"]',
            'Expected dojox.grid table'
        );

        // verify add and reset buttons appear
        // verify save and restore buttons appear
        $this->assertQueryContentContains(
            "div.button button.add-button",
            "Add Workflow",
            "Expected existence of Add Workflow button."
        );
        $this->assertQueryContentContains(
            "div.button button",
            "Reset to Defaults",
            "Expected existence of Reset to Defaults button."
        );

        // check initial JSON output
        $this->resetRequest()
             ->resetResponse();
        $this->dispatch('/workflow/format/json');
        $body = $this->response->getBody();
        $this->assertModule('workflow', 'Expected module, dispatch #2. '. $body);
        $this->assertController('index', 'Expected controller, dispatch #2 '. $body);
        $this->assertAction('index', 'Expected action, dispatch #2 '. $body);

        // verify there are no items in the grid
        $data = Zend_Json::decode($body);
        $this->assertSame(
            array(),
            $data['items'],
            'Expected no workflows.'
        );

        // add few workflows and verify they appear
        $this->_createWorkflow('test');
        $this->_createWorkflow('foo');

        $this->resetRequest()
             ->resetResponse();
        // sort by label
        $this->dispatch('/workflow/format/json?sort=label');
        $body = $this->response->getBody();
        $this->assertModule('workflow', 'Expected module, dispatch #3. '. $body);
        $this->assertController('index', 'Expected controller, dispatch #3 '. $body);
        $this->assertAction('index', 'Expected action, dispatch #3 '. $body);

        $data = Zend_Json::decode($body);
        $expected = array(
            0 => array(
                'id'            => 'foo',
                'label'         => 'foo label',
                'description'   => 'foo description',
                'states'        => array(),
                'contentTypes'  => array()
            ),
            1 => array(
                'id'            => 'test',
                'label'         => 'test label',
                'description'   => 'test description',
                'states'        => array(),
                'contentTypes'  => array()
            )
        );

        $this->assertEquals(
            $expected,
            $data['items'],
            'Expected 2 workflows.'
        );
    }

    /**
     * Test the add action.
     */
    public function testAdd()
    {
        $this->utility->impersonate('editor');

        // verify form markup for different contexts
        $contexts = array(null, 'partial');
        foreach ($contexts as $context) {
            $format = $context ? "/format/$context" : "";

            $this->resetRequest()
                 ->resetResponse();            
            $this->dispatch('/workflow/add' . $format);

            $this->assertModule('workflow', 'Expected module.');
            $this->assertController('index', 'Expected controller');
            $this->assertAction('add', 'Expected action');

            // ensure that form inputs are presented correctly
            $this->assertQuery("form.workflow-form",                "Expected add form.");
            foreach ($this->_getWorkflowFormElementsType() as $field => $type) {
                $query = $type !== 'textarea' ? 'input' : $type;
                $this->assertQuery("{$query}[name='$field']",       "Expected '$field' input.");
            }
            $this->assertQuery("input[type='submit']",              "Expected submit button.");

            // ensure labels are present.
            $labels = array(
                'id'            => 'Id',
                'label'         => 'Label',
                'description'   => 'Description',
                'states'        => 'States'
            );
            foreach ($labels as $field => $label) {
                $this->assertQueryContentContains("label[for='$field']", $label, "Expected $field label.");
            }
        }
    }

    /**
     * Test bogus post to add.
     */
    public function testBadAddPost()
    {
        $this->utility->impersonate('editor');

        // add workflow to allow testing for unique id
        $this->_createWorkflow('test');

        $tests   = $this->_getTestWorkflowFormBadData();
        $tests[] = array(
            'values'        => array(
                'id'            => 'test',
                'label'         => 'foo',
                'description'   => 'bar',
                'states'        => "[baz] label = baz",
            ),
            'errorsCount'   => 1,
            'message'       => 'Id already exists'
        );

        // loop throught all tests
        foreach ($tests as $test) {
            $this->_verifyBadPost('/workflow/add', 'add', $test);
        }
    }

    /**
     * Test good post to add.
     */
    public function testGoodAddPost()
    {
        $this->utility->impersonate('editor');

        $tests = $this->_getTestWorkflowFormGoodData();

        // loop throught all tests
        foreach ($tests as $test) {
            $this->_verifyGoodPost('/workflow/add', 'add', $test);
        }
    }

    /**
     * Test bad post to edit.
     */
    public function testBadEditPost()
    {
        $this->utility->impersonate('editor');

        $workflow = $this->_createWorkflow('foo');
        $workflow->setValue('states', '[foo]\nlabel=foo label')
                 ->save();

        $tests = $this->_getTestWorkflowFormBadData();

        // loop throught all tests
        foreach ($tests as $test) {
            // skip tests with 1 error due to wrong id as id for edit is provided from url
            if (isset($test['idError']) && $test['idError'] === true) {
                $test['errorsCount']--;
            }

            if ($test['errorsCount'] == 0) {
                continue;
            }

            $this->_verifyBadPost('/workflow/edit/id/foo', 'edit', $test);
        }
    }

    /**
     * Test edit with bad workflow id.
     */
    public function testBadEditId()
    {
        $this->utility->impersonate('editor');

        $this->request->setParam('id', 'noexist');
        $this->dispatch('/workflow/edit');
        $this->assertModule('error',     'Expected module.');
        $this->assertController('index', 'Expected controller.');
        $this->assertAction('error',     'Expected action.');
    }

    /**
     * Test good post to edit.
     */
    public function testGoodEditPost()
    {
        $this->utility->impersonate('editor');

        $workflow = $this->_createWorkflow('bar');
        $workflow->setValue('states', '[bar]\nlabel=bar label')
                 ->save();

        $tests = $this->_getTestWorkflowFormGoodData();

        // loop throught all tests
        foreach ($tests as $test) {
            $this->_verifyGoodPost('/workflow/edit/id/bar', 'edit', $test);
        }
    }

    /**
     * Test delete action with invalid id.
     */
    public function testDeleteInvalidId()
    {
        $this->utility->impersonate('editor');

        $this->request->setMethod('POST');
        $this->dispatch('/workflow/delete/id/does-not-exist');
        $this->assertModule('error',        __LINE__ .': Last module run should be error module.');
        $this->assertController('index',    __LINE__ .': Expected controller');
        $this->assertAction('error',        __LINE__ .': Expected action');
    }

    /**
     * Test delete action with anonymous access.
     */
    public function testDeleteByAnonymous()
    {
        $this->_createWorkflow('test');

        $this->request->setMethod('POST');
        $this->request->setParam('id', 'test');
        $this->dispatch('/workflow/delete');
        $this->assertModule('error',            __LINE__ .': Last module run should be error module.');
        $this->assertController('index',        __LINE__ .': Expected controller');
        $this->assertAction('access-denied',    __LINE__ .': Expected action');

        // verify workflow record has not been deleted
        $this->assertTrue(
            Workflow_Model_Workflow::exists('test'),
            "Expected test workflow has not been deleted."
        );
    }

    /**
     * Test deleting an invalid request method
     */
    public function testDeleteInvalidRequestMethod()
    {
        $this->_createWorkflow('foo');
        
        $this->request->setMethod('GET');
        $this->dispatch('/workflow/delete/id/foo');
        $this->assertModule('error', 'Expected error module.');
    }

    /**
     * Test deleting workflow.
     */
    public function testDelete()
    {
        $this->utility->impersonate('editor');
        $this->_createWorkflow('delete');
        $this->_createWorkflow('no-delete');

        $this->request->setMethod('POST');
        $this->request->setParam('id', 'delete');
        $this->dispatch('/workflow/delete');

        $this->assertModule('workflow',     'Expected module.');
        $this->assertController('index',    'Expected controller');
        $this->assertAction('delete',       'Expected action');

        // should redirect to the previous page (base url in this case)
        $this->assertRedirectTo('/workflow/manage', 'Expect redirect to manage page.');

        // verify workflow records after delete
        $this->assertFalse(
            Workflow_Model_Workflow::exists('delete'),
            "Expected delete workflow has been deleted."
        );
        $this->assertTrue(
            Workflow_Model_Workflow::exists('no-delete'),
            "Expected no-delete workflow has not been deleted."
        );
    }

    /**
     * Test deleting workflow in json context.
     */
    public function testDeleteJson()
    {
        $this->utility->impersonate('editor');
        $this->_createWorkflow('del');
        $this->_createWorkflow('del1');

        $this->request->setMethod('POST');
        $this->request->setPost(
            array(
                'id' =>     'del1',
                'format' => 'json'
            )
        );
        $this->dispatch('/workflow/delete');

        $this->assertModule('workflow',     'Expected module.');
        $this->assertController('index',    'Expected controller');
        $this->assertAction('delete',       'Expected action');

        // when delete in context, no redirecting should be made
        $this->assertNotRedirect(
            "Expected user is not redirected after workflow delete if within a context."
        );

        $responseBody = $this->response->getBody();
        $this->assertEquals(
            Zend_Json::encode(array('id' => 'del1')),
            $responseBody,
            __LINE__ .': Expected json output.'
        );
        
        // verify workflow records after delete
        $this->assertFalse(
            Workflow_Model_Workflow::exists('del1'),
            "Expected del1 workflow has been deleted."
        );
        $this->assertTrue(
            Workflow_Model_Workflow::exists('del'),
            "Expected del workflow has not been deleted."
        );
    }

    /**
     * Test workflows reset action.
     */
    public function testReset()
    {
        $this->utility->impersonate('editor');

        $workflows = array('workflow1', 'workflow2');
        foreach ($workflows as $workflow) {
            $this->_createWorkflow($workflow);
        }

        // ensure worflows are there
        foreach ($workflows as $workflow) {
            $this->assertTrue(
                Workflow_Model_Workflow::exists($workflow),
                "Expected '$workflow' workflow exists."
            );
        }

        // reset workflows
        $this->dispatch('/workflow/reset');

        $this->assertModule('workflow',     'Expected module when workflow reset.');
        $this->assertController('index',    'Expected controller when workflow reset.');
        $this->assertAction('reset',        'Expected action when workflow reset.');

        // ensure there are only default workflows
        $defaultWorkflows = Workflow_Model_Workflow::fetchAll();
        $this->assertEquals(
            1,
            $defaultWorkflows->count(),
            "Expected 1 workflow after reset."
        );
        $this->assertTrue(
            Workflow_Model_Workflow::exists('simple'),
            "Expected presence of 'Simple' workflow after reset"
        );
    }

    /**
     * Return array with types of workflow form elements.
     */
    protected function _getWorkflowFormElementsType()
    {
        return array(
            'id'            => 'text',
            'label'         => 'text',
            'description'   => 'textarea',
            'states'        => 'textarea'
        );
    }

    /**
     * Create sample workflow record.
     *
     * @param   string          $id         Id of created workflow.
     * @return  Workflow_Model_Workflow     Instance of newly created workflow.
     */
    protected function _createWorkflow($id)
    {
        return Workflow_Model_Workflow::store(
            array(
                'id'            => "$id",
                'label'         => "$id label",
                'description'   => "$id description"
            )
        );
    }

    /**
     * Return list with bogus data suitable for testing the workflow form.
     */
    protected function _getTestWorkflowFormBadData()
    {
        // following data are suitable for testing both add and edit actions,
        // however as id is provided from url for edit action, there must be
        // an extra flag (idError = true) set if id error contributes to the
        // total amount of errors (errorsCount)
        $data = array(
            array(
                'values'        => array(),
                'errorsCount'   => 3,
                'idError'       => true,
                'message'       => 'Missing required fields #1'
            ),
            array(
                'values'        => array(
                    'description'   => 'test desc'
                ),
                'errorsCount'   => 3,
                'idError'       => true,
                'message'       => 'Missing required fields #2'
            ),
            array(
                'values'        => array(
                    'id'            => 'foo'
                ),
                'errorsCount'   => 2,
                'message'       => 'Missing required fields #3'
            ),
            array(
                'values'        => array(
                    'label'         => 'foo',
                    'description'   => 'foo desc',
                    'states'        => "[foo] label = bar",
                ),
                'errorsCount'   => 1,
                'idError'       => true,
                'message'       => 'Missing id'
            ),
            array(
                'values'        => array(
                    'id'            => '#$%^',
                    'label'         => 'foo',
                    'states'        => '[a]'
                ),
                'errorsCount'   => 1,
                'idError'       => true,
                'message'       => 'Wrong id #1'
            ),
            array(
                'values'        => array(
                    'id'            => '@1',
                    'label'         => 'foo',
                    'description'   => 'bar',
                    'states'        => '[baz]'
                ),
                'errorsCount'   => 1,
                'idError'       => true,
                'message'       => 'Wrong id #2'
            ),
            array(
                'values'        => array(
                    'id'            => 'spaces not allowed',
                    'label'         => 'foo',
                    'description'   => 'foo desc',
                    'states'        => "[foo] label = bar",
                ),
                'errorsCount'   => 1,
                'idError'       => true,
                'message'       => 'Wrong id #3'
            ),
            array(
                'values'        => array(
                    'id'            => 'bar',
                    'label'         => 'Bar',
                    'description'   => 'bar desc',
                    'states'        => "state",
                ),
                'errorsCount'   => 1,
                'message'       => 'Wrong states field (at least one state has to be defined)'
            ),
            array(
                'values'        => array(
                    'id'            => 'bar',
                    'label'         => 'Bar',
                    'description'   => 'bar desc',
                    'states'        => "label=w",
                ),
                'errorsCount'   => 1,
                'message'       => 'Wrong states field (at least one state has to be defined)'
            ),
            array(
                'values'        => array(
                    'id'            => 'baz',
                    'label'         => 'Baz baz',
                    'description'   => 'bazzzZZZzzz',
                    'states'        => "[state label = baz",
                ),
                'errorsCount'   => 1,
                'message'       => 'Wrong states field (not a valid INI format)'
            )
        );
        return $data;
    }

    /**
     * Return list with good data suitable for testing the workflow form.
     */
    protected function _getTestWorkflowFormGoodData()
    {
        $data = array(
            array(
                'values'        => array(
                    'id'            => 'foo',
                    'label'         => 'foo label',
                    'states'        => "[foo] label = bar",
                ),
            ),
            array(
                'values'        => array(
                    'id'            => 'bar',
                    'label'         => 'bar label',
                    'description'   => 'bar desc',
                    'states'        => "[bar]\nlabel = baz\n[foo]\nlabel = another baz",
                ),
            ),
            array(
                'values'        => array(
                    'id'            => 'baz',
                    'label'         => 'baz label',
                    'states'        => "[123] a=b",
                ),
            ),
            array(
                'values'        => array(
                    'id'            => 'test',
                    'label'         => 'x',
                    'description'   => 'y',
                    'states'        => "[ab c]",
                ),
            )
        );
        return $data;
    }

    /**
     * Dispatch to provided url with provided post data and verify that form contains errors.
     * 
     * @param string    $url        Url to dispatch to.
     * @param string    $action     Workflow action.
     * @param array     $data       Array containing post data, expected number of errors
     *                              and message for assert output.
     */
    protected function _verifyBadPost($url, $action, array $data)
    {
        $this->resetRequest()
             ->resetResponse();
        $this->request->setMethod('POST');
        $this->request->setPost($data['values']);

        $this->dispatch($url);
        $this->assertModule('workflow',     'Expected module.');
        $this->assertController('index',    'Expected controller');
        $this->assertAction($action,        'Expected action');
        $this->assertResponseCode(400,      'Expected bad request response code.');

        // check form errors
        $this->assertQuery("#layout-main form.workflow-form", "Expected add form.");
        $this->assertQueryCount(
            "ul.errors",
            $data['errorsCount'],
            "Expected {$data['errorsCount']} form errors for test '{$data['message']}'."
        );

        // edit form should always preserve id from url
        if ($action === 'edit') {
            $data['values']['id'] = $this->getRequest()->getParam('id');
        }

        // ensure posted data were preserved            
        $elementTypes = $this->_getWorkflowFormElementsType();
        foreach ($data['values'] as $field => $value) {
            $query = $elementTypes[$field] == 'textarea'
                ? "dd textarea[name='$field']"
                : "dd#$field-element";
            $this->assertQueryContentContains(
                "form.workflow-form $query",
                $value,
                "Expected preserving of value '$value' for '$field' field for test '{$data['message']}'."
            );
        }
    }

    /**
     * Dispatch to provided url with provided post data and verify that form values have been saved.
     *
     * @param string    $url        Url to dispatch to.
     * @param string    $action     Workflow action.
     * @param array     $data       Array containing post data.
     */
    protected function _verifyGoodPost($url, $action, array $data)
    {
        $this->resetRequest()
             ->resetResponse();
        $this->request->setMethod('POST');
        $this->request->setPost($data['values']);

        $this->dispatch($url);
        $this->assertModule('workflow',     'Expected module.');
        $this->assertController('index',    'Expected controller');
        $this->assertAction($action,        'Expected action');

        // expect redirect to previous page (base url)
        $this->assertRedirectTo('/workflow/manage', 'Expect redirect to manage page.');

        // edit form should always preserve id from url
        if ($action === 'edit') {
            $data['values']['id'] = $this->getRequest()->getParam('id');
        }

        // verify workflow record has been saved
        $this->assertTrue(
            Workflow_Model_Workflow::exists($data['values']['id']),
            "Expected workflow record has been saved/updated."
        );

        // verify model values
        $workflow = Workflow_Model_Workflow::fetch($data['values']['id']);
        foreach ($data['values'] as $field => $value) {
            // states are by default returned as list of state models
            $workflowValue = $field == 'states'
                ? $workflow->getStatesAsIni()
                : $workflow->getValue($field);

            $this->assertSame(
                $value,
                $workflowValue,
                "Expected value of '$field' returned by workflow model."
            );
        }
    }
}
# Change User Description Committed
#1 16170 perforce_software Move Chronicle files to follow new path scheme for branching.
//guest/perforce_software/chronicle/application/workflow/tests/IndexControllerTest.php
#1 8972 Matt Attaway Initial add of the Chronicle source code