Perforce Chronicle 2012.2/486814
API Documentation

Category_Test_ManageControllerTest Class Reference

Test the category manage controller. More...

List of all members.

Public Member Functions

 testAddBadParentPost ()
 Test add with a bad parent.
 testAddBadPost ()
 Test add with a post missing several required fields.
 testAddConflictingTitle ()
 Test add- with a conflicting title.
 testAddGoodPostJson ()
 Test add with a good post w.
 testAddNoPost ()
 Test the add action without a post.
 testComposedFilter ()
 Test multi-filtering.
 testDelete ()
 Test deleting.
 testEditBadPost ()
 Test edit with bad post.
 testEditNoPost ()
 Test edit with no post.
 testFilterByCategoryEntries ()
 Test filtering grid by number of category entries.
 testFilterBySearch ()
 Test filtering grid by search query.
 testGoodAddPost ()
 Test add with a good post.
 testGoodEditPost ()
 Test good post to edit.
 testIndex ()
 Test the index action.

Protected Member Functions

 _getItemById ($id, array $data, $key=null)
 Helper function for getting item with given id from json decoded data.
 _makeContent (array $entries)
 Test helper method to create specified content records.
 _setupFiltering ()
 Creates categories and assigned content for testing filtering options.

Detailed Description

Test the category manage controller.

Copyright:
2011-2012 Perforce Software. All rights reserved
License:
Please see LICENSE.txt in top-level folder of this distribution.
Version:
2012.2/486814

Member Function Documentation

Category_Test_ManageControllerTest::_getItemById ( id,
array $  data,
key = null 
) [protected]

Helper function for getting item with given id from json decoded data.

Parameters:
string$idid to search for between items in the data
array$dataarray to search item with given id for
string$keyoptional - if set then item[key] will be returned, where item is one of the items in data with item['id'] matches the given id, otherwise the whole item will be returned
Returns:
array|string data item with id matching the passed value or value of item[key]
    {
        $callback = function($item) use ($id)
        {
            return isset($item['id']) && $item['id'] === $id;
        };
        $found = current(array_filter($data['items'], $callback));
        return $key ? $found[$key] : $found;
    }
Category_Test_ManageControllerTest::_makeContent ( array $  entries) [protected]

Test helper method to create specified content records.

Parameters:
array$entriesAn array of id => title for the content records to create.
Returns:
array An array of the created content entries.
    {
        $created = array();
        foreach ($entries as $id => $title) {
            $entry = new P4Cms_Content;
            $entry->setId($id)
                  ->setValue('contentType', 'basic-page')
                  ->setValue('title', $title)
                  ->save();
            $created[] = $entry;
        }

        return $created;
    }
Category_Test_ManageControllerTest::_setupFiltering ( ) [protected]

Creates categories and assigned content for testing filtering options.

    {
        // create folowing categories structure:
        // A
        // B
        //   subB-last
        // C
        //   subC
        //     subsubC-last
        Category_Model_Category::store(
            array(
                'title' => 'A',
                'id'    => 'A'
            )
        );
        Category_Model_Category::store(
            array(
                'title' => 'B',
                'id'    => 'B'
            )
        );
        Category_Model_Category::store(
            array(
                'title' => 'subB-last',
                'id'    => 'B/subB-last'
            )
        );
        Category_Model_Category::store(
            array(
                'title' => 'C',
                'id'    => 'C'
            )
        );
        Category_Model_Category::store(
            array(
                'title' => 'subC',
                'id'    => 'C/subC'
            )
        );
        Category_Model_Category::store(
            array(
                'title' => 'subsubC-last',
                'id'    => 'C/subC/subsubC-last'
            )
        );

        // create content entry and assign the B and subC category to it
        P4Cms_Content::store(
            array(
                'id'    => 'test'
            )
        );
        Category_Model_Category::setEntryCategories('test', array('B', 'C/subC'));
    }
Category_Test_ManageControllerTest::testAddBadParentPost ( )

Test add with a bad parent.

    {
        $this->utility->impersonate('author');

        // form request without required fields.
        $this->request->setMethod('POST');
        $this->request->setPost('title',       'Test Category');
        $this->request->setPost('parent',      'lasdjkfasdklf');
        $this->request->setPost('description', 'a description');
        $this->request->setPost(P4Cms_Form::CSRF_TOKEN_NAME, P4Cms_Form::getCsrfToken());
        $this->dispatch('/category/manage/add');

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

        // check for form w. errors.
        $this->assertQuery('form.category-form', 'Expected add form.');
        $this->assertQueryCount('ul.errors', 1, 'Expected one error.');

        $this->assertQueryContentContains('li', "'lasdjkfasdklf' is not a valid parent category.");

        // ensure elements value was preserved.
        $this->assertQueryContentContains('textarea', 'a description');
    }
Category_Test_ManageControllerTest::testAddBadPost ( )

Test add with a post missing several required fields.

    {
        $this->utility->impersonate('author');

        // form request without required fields.
        $this->request->setMethod('POST');
        $this->request->setPost('description', 'test description');
        $this->request->setPost(P4Cms_Form::CSRF_TOKEN_NAME, P4Cms_Form::getCsrfToken());
        $this->dispatch('/category/manage/add');
        $this->assertModule('category', 'Expected module.');
        $this->assertController('manage', 'Expected controller');
        $this->assertAction('add', 'Expected action');

        // check for form w. errors.
        $this->assertQuery('form.category-form', 'Expected add form.');
        $this->assertQueryCount('ul.errors', 1, 'Expected matching number of errors.');

        // ensure description value was preserved.
        $this->assertQueryContentContains('textarea', 'test description');
    }
Category_Test_ManageControllerTest::testAddConflictingTitle ( )

Test add- with a conflicting title.

    {
        $this->utility->impersonate('author');

        // create a category to show up in the parent select
        Category_Model_Category::store(
            array(
                'id'            => 'foo',
                'title'         => 'Foobulous',
                'description'   => 'Foobulous'
            )
        );

        // form request with appropriate fields.
        $this->request->setMethod('POST');
        $this->request->setPost('title',       'Foo');
        $this->request->setPost('parent',      '/');
        $this->request->setPost(P4Cms_Form::CSRF_TOKEN_NAME, P4Cms_Form::getCsrfToken());
        $this->dispatch('/category/manage/add');
        $this->assertModule('category', 'Expected module.');
        $this->assertController('manage', 'Expected controller');
        $this->assertAction('add', 'Expected action');

        // check for form w. errors.
        $this->assertQuery('form.category-form', 'Expected add form.');
        $this->assertQueryCount('ul.errors', 1, 'Expected one error.');
    }
Category_Test_ManageControllerTest::testAddGoodPostJson ( )

Test add with a good post w.

JSON

    {
        $this->utility->impersonate('author');

        // form request without required fields.
        $title = 'Good Category';
        $this->request->setMethod('POST');
        $this->request->setPost('title',  $title);
        $this->request->setPost('parent', '');
        $this->request->setPost('format', 'json');
        $this->request->setPost(P4Cms_Form::CSRF_TOKEN_NAME, P4Cms_Form::getCsrfToken());
        
        $this->dispatch('/category/manage/add');
        $this->assertModule('category', 'Expected module.');
        $this->assertController('manage', 'Expected controller');
        $this->assertAction('add', 'Expected action');

        // check for saved category entry.
        $id = 'good-category';
        $this->assertTrue(Category_Model_Category::exists($id), 'Expected category to be saved.');
        $category = Category_Model_Category::fetch($id);
        $this->assertSame(
            $title,
            $category->getValue('title'),
            'Expected same title as was posted.'
        );

        $body = $this->response->getBody();
        $this->assertResponseCode(200, 'Expected success response code for post');
        $data = json_decode($body, true);

        // verify that arrays of category in json and saved category are same (items order can differ)
        $this->assertSame(
            count($data['category']),
            count($category->toArray()),
            'Expected number of items in category in json and in saved category are the same.'
        );
        $this->assertSame(
            array(),
            array_diff($category->toArray(), $data['category']),
            'Expected items in category in json response and in saved category are the same.'
        );
    }
Category_Test_ManageControllerTest::testAddNoPost ( )

Test the add action without a post.

    {
        $this->utility->impersonate('author');

        // create a category to show up in the parent select
        Category_Model_Category::store(
            array(
                'id'            => 'foo',
                'title'         => 'Foo',
                'description'   => 'Foobulous'
            )
        );

        $this->dispatch('/category/manage/add');
        $this->assertModule('category', 'Expected module.');
        $this->assertController('manage', 'Expected controller');
        $this->assertAction('add', 'Expected action');

        // ensure that form inputs are presented correctly.
        $this->assertQuery('form.category-form', 'Expected add form.');
        $this->assertQuery('select[name="parent"]', 'Expected handler select input.');
        $this->assertQueryCount('select[name="parent"] option', 2, 'Expected two parents.');
        $this->assertQuery('input[name="title"]', 'Expected label input.');
        $this->assertQuery('textarea[name="description"]', 'Expected description input.');
        $this->assertQuery('input[type="submit"]', 'Expected submit button.');

        // ensure labels are present.
        $labels = array(
            'title'       => 'Title',
            'parent'      => 'Parent',
            'description' => 'Description',
        );
        foreach ($labels as $field => $label) {
            $this->assertQueryContentContains("label[for='$field']", $label, 'Expected $field label.');
        }
    }
Category_Test_ManageControllerTest::testComposedFilter ( )

Test multi-filtering.

    {
        $this->utility->impersonate('editor');

        // setup environment for testing
        $this->_setupFiltering();

        $this->dispatch('/category/manage/format/json?search[query]=sub&entriesCount[display]=more');
        $body = $this->response->getBody();
        $this->assertModule('category', 'Expected module, dispatch #1. '. $body);
        $this->assertController('manage', 'Expected controller, dispatch #1 '. $body);
        $this->assertAction('index', 'Expected action, dispatch #1 '. $body);

        // decode json output
        $data = Zend_Json::decode($body);

        // expected items (* denotes obligatory): C(*), C/subC
        $obligatoryLogicMap = array(
            'C'                     => 1,
            'C/subC'                => 0,
        );

        // verify number of items after filtering
        $this->assertSame(
            count($obligatoryLogicMap),
            count($data['items']),
            'Expected number of items after multi-filtering #1.'
        );

        // verify obligatory items are marked
        foreach ($obligatoryLogicMap as $id => $isObligatory) {
            $assertFunction = $isObligatory ? 'assertTrue' : 'assertFalse';
            $this->$assertFunction(
                $this->_getItemById($id, $data, 'obligatory'),
                "Expected category $id " . ($isObligatory ? 'is' : 'is not')
                    . " marked as obligatory after multi-filtering #1"
            );
        }

        // test with another search query
        $this->resetRequest()
             ->resetResponse();

        $this->dispatch('/category/manage/format/json?search[query]=last&entriesCount[display]=more');
        $body = $this->response->getBody();
        $this->assertModule('category', 'Expected module, dispatch #2. '. $body);
        $this->assertController('manage', 'Expected controller, dispatch #2 '. $body);
        $this->assertAction('index', 'Expected action, dispatch #2 '. $body);

        // decode json output
        $data = Zend_Json::decode($body);

        // expected items (* denotes obligatory): empty
        $obligatoryLogicMap = array();

        // verify number of items after filtering
        $this->assertSame(
            count($obligatoryLogicMap),
            count($data['items']),
            'Expected number of items after multi-filtering #2.'
        );

        // verify obligatory items are marked
        foreach ($obligatoryLogicMap as $id => $isObligatory) {
            $assertFunction = $isObligatory ? 'assertTrue' : 'assertFalse';
            $this->$assertFunction(
                $this->_getItemById($id, $data, 'obligatory'),
                "Expected category $id " . ($isObligatory ? 'is' : 'is not')
                    . " marked as obligatory after multi-filtering #2"
            );
        }
    }
Category_Test_ManageControllerTest::testDelete ( )

Test deleting.

    {
        $this->utility->impersonate('editor');

        // create category to be edited.
        Category_Model_Category::store(array('id' => 'editme', 'title' => 'Edit Me'));
        Category_Model_Category::store(array('id' => 'editme/subcat', 'title' => 'subCat', 'description' => 'docs'));

        $this->request->setMethod('POST');
        $this->request->setParam('category', 'editme');
        $this->request->setParam('format',   'json');
        $this->request->setPost(P4Cms_Form::CSRF_TOKEN_NAME, P4Cms_Form::getCsrfToken());
        $this->dispatch('/category/manage/delete');
        $this->assertModule('category', 'Expected module.');
        $this->assertController('manage', 'Expected controller');
        $this->assertAction('delete', 'Expected action');

        // ensure categories gone.
        $this->assertFalse(
            Category_Model_Category::exists('editme/subcat'),
            "Expected category editme/subcat not to exist post delete."
        );
        $this->assertFalse(
            Category_Model_Category::exists('editme'),
            "Expected category editme not to exist post delete."
        );
    }
Category_Test_ManageControllerTest::testEditBadPost ( )

Test edit with bad post.

    {
        $this->utility->impersonate('editor');

        // create category to be edited.
        Category_Model_Category::store(array('id' => 'edit-me', 'title' => 'Edit Me'));
        Category_Model_Category::store(array('id' => 'edit-me/subcat', 'title' => 'subCat', 'description' => 'docs'));

        // form request without required field (elements).
        $this->request->setParam('category', 'edit-me/subcat');
        $this->request->setMethod('POST');
        $this->request->setPost('title',       '');
        $this->request->setPost('description', 'changed');
        $this->request->setPost(P4Cms_Form::CSRF_TOKEN_NAME, P4Cms_Form::getCsrfToken());

        $this->dispatch('/category/manage/edit');
        $this->assertModule('category', 'Expected module.');
        $this->assertController('manage', 'Expected controller');
        $this->assertAction('edit', 'Expected action');

        // check for form w. errors.
        $this->assertQuery('form', 'Expected edit form.');
        $this->assertQueryCount('ul.errors', 1, 'Expected one error.');

        // ensure label value was preserved.
        $this->assertQuery('//input[@name="title"][@value=""]', 'Expect title to be changed.');
    }
Category_Test_ManageControllerTest::testEditNoPost ( )

Test edit with no post.

    {
        $this->utility->impersonate('editor');

        // test editing an id that does not exist
        $id = 'editme/subcat';
        $this->request->setParam('category', $id);
        $this->dispatch('/category/manage/edit');
        $this->assertModule('error', 'Expected module.');
        $this->assertController('index', 'Expected controller');
        $this->assertAction('error', 'Expected action');

        $this->resetRequest()->resetResponse();

        // test editing an id that does exist.
        Category_Model_Category::store(array('id' => 'editme', 'title' => 'Edit Me'));
        Category_Model_Category::store(array('id' => 'editme/subcat', 'title' => 'subCat', 'description' => 'docs'));
        $this->request->setParam('category', $id);
        $this->dispatch('/category/manage/edit');
        $this->assertModule('category', 'Expected module.');
        $this->assertController('manage', 'Expected controller');
        $this->assertAction('edit', 'Expected action');

        $this->assertQueryContentContains('select[name="parent"] option', 'Edit Me', 'Expected parent input.');
        $this->assertXpath('//input[@name="title"][@value="subCat"]', 'Expected title input.');
        $this->assertQueryContentContains('textarea[name="description"]', 'docs', 'Expected description input.');
    }
Category_Test_ManageControllerTest::testFilterByCategoryEntries ( )

Test filtering grid by number of category entries.

    {
        $this->utility->impersonate('editor');

        // setup environment for testing
        $this->_setupFiltering();

        // show only non-empty categories
        $this->dispatch('/category/manage/format/json?entriesCount[display]=more');
        $body = $this->response->getBody();
        $this->assertModule('category', 'Expected module, dispatch #1. '. $body);
        $this->assertController('manage', 'Expected controller, dispatch #1 '. $body);
        $this->assertAction('index', 'Expected action, dispatch #1 '. $body);

        // decode json output
        $data = Zend_Json::decode($body);

        // expected items (* denotes obligatory): B, C(*), C/subC
        $obligatoryLogicMap = array(
            'B'                     => 0,
            'C'                     => 1,
            'C/subC'                => 0,
        );

        // verify number of items after filtering
        $this->assertSame(
            count($obligatoryLogicMap),
            count($data['items']),
            'Expected number of items after filtering by category entries #1.'
        );

        // verify obligatory items are marked
        foreach ($obligatoryLogicMap as $id => $isObligatory) {
            $assertFunction = $isObligatory ? 'assertTrue' : 'assertFalse';
            $this->$assertFunction(
                $this->_getItemById($id, $data, 'obligatory'),
                "Expected category $id " . ($isObligatory ? 'is' : 'is not')
                    . " marked as obligatory after filtering by category entries #1"
            );
        }

        // test with another filter
        $this->resetRequest()
             ->resetResponse();

        // show only empty categories
        $this->dispatch('/category/manage/format/json?entriesCount[display]=none');
        $body = $this->response->getBody();
        $this->assertModule('category', 'Expected module, dispatch #2. '. $body);
        $this->assertController('manage', 'Expected controller, dispatch #2 '. $body);
        $this->assertAction('index', 'Expected action, dispatch #2 '. $body);

        // decode json output
        $data = Zend_Json::decode($body);

        // expected items (* denotes obligatory): A, B(*), B/subB-last, C, C/subC(*), C/subC/subsubC-last
        $obligatoryLogicMap = array(
            'A'                     => 0,
            'B'                     => 1,
            'B/subB-last'           => 0,
            'C'                     => 0,
            'C/subC'                => 1,
            'C/subC/subsubC-last'   => 0
        );

        // verify number of items after filtering
        $this->assertSame(
            count($obligatoryLogicMap),
            count($data['items']),
            'Expected number of items after filtering by category entries #2.'
        );

        // verify obligatory items are marked
        foreach ($obligatoryLogicMap as $id => $isObligatory) {
            $assertFunction = $isObligatory ? 'assertTrue' : 'assertFalse';
            $this->$assertFunction(
                $this->_getItemById($id, $data, 'obligatory'),
                "Expected category $id " . ($isObligatory ? 'is' : 'is not')
                    . " marked as obligatory after filtering by category entries #2"
            );
        }
    }
Category_Test_ManageControllerTest::testFilterBySearch ( )

Test filtering grid by search query.

    {
        $this->utility->impersonate('editor');

        // setup environment for testing
        $this->_setupFiltering();

        $this->dispatch('/category/manage/format/json?search[query]=last');
        $body = $this->response->getBody();
        $this->assertModule('category', 'Expected module, dispatch #1. '. $body);
        $this->assertController('manage', 'Expected controller, dispatch #1 '. $body);
        $this->assertAction('index', 'Expected action, dispatch #1 '. $body);

        // decode json output
        $data = Zend_Json::decode($body);

        // expected items (* denotes obligatory): B(*), B/subB, C(*), C/subC(*), C/subC/subsubC-last
        $obligatoryLogicMap = array(
            'B'                     => 1,
            'B/subB-last'           => 0,
            'C'                     => 1,
            'C/subC'                => 1,
            'C/subC/subsubC-last'   => 0
        );

        // verify number of items after filtering
        $this->assertSame(
            count($obligatoryLogicMap),
            count($data['items']),
            'Expected number of items after filtering by search #1.'
        );

        // verify obligatory items are marked
        foreach ($obligatoryLogicMap as $id => $isObligatory) {
            $assertFunction = $isObligatory ? 'assertTrue' : 'assertFalse';
            $this->$assertFunction(
                $this->_getItemById($id, $data, 'obligatory'),
                "Expected category $id " . ($isObligatory ? 'is' : 'is not') 
                    . " marked as obligatory after filtering by search #1"
            );
        }

        // test with another search query
        $this->resetRequest()
             ->resetResponse();

        $this->dispatch('/category/manage/format/json?search[query]=subc');
        $body = $this->response->getBody();
        $this->assertModule('category', 'Expected module, dispatch #2. '. $body);
        $this->assertController('manage', 'Expected controller, dispatch #2 '. $body);
        $this->assertAction('index', 'Expected action, dispatch #2 '. $body);

        // decode json output
        $data = Zend_Json::decode($body);

        // expected items (* denotes obligatory): C(*), C/subC, C/subC/subsubC-last
        $obligatoryLogicMap = array(
            'C'                     => 1,
            'C/subC'                => 0,
            'C/subC/subsubC-last'   => 0
        );

        // verify number of items after filtering
        $this->assertSame(
            count($obligatoryLogicMap),
            count($data['items']),
            'Expected number of items after filtering by search #2.'
        );

        // verify obligatory items are marked
        foreach ($obligatoryLogicMap as $id => $isObligatory) {
            $assertFunction = $isObligatory ? 'assertTrue' : 'assertFalse';
            $this->$assertFunction(
                $this->_getItemById($id, $data, 'obligatory'),
                "Expected category $id " . ($isObligatory ? 'is' : 'is not')
                    . " marked as obligatory after filtering by search #2"
            );
        }
    }
Category_Test_ManageControllerTest::testGoodAddPost ( )

Test add with a good post.

    {
        $this->utility->impersonate('author');

        // form request without required fields.
        $title       = 'Good Category';
        $id          = 'good-category';
        $description = 'a description';
        $this->request->setMethod('POST');
        $this->request->setPost('title',       $title);
        $this->request->setPost('parent',      '');
        $this->request->setPost('description', $description);
        $this->request->setPost(P4Cms_Form::CSRF_TOKEN_NAME, P4Cms_Form::getCsrfToken());

        $this->dispatch('/category/manage/add');
        $this->assertModule('category', 'Expected module.');
        $this->assertController('manage', 'Expected controller');
        $this->assertAction('add', 'Expected action');

        // check for saved category entry.
        $this->assertTrue(Category_Model_Category::exists($id), 'Expected category to be saved.');
        $category = Category_Model_Category::fetch($id);
        $this->assertSame(
            $title,
            $category->getValue('title'),
            'Expected same title as was posted.'
        );
        $this->assertSame(
            $description,
            $category->getValue('description'),
            'Expected same description as was posted.'
        );

        $this->resetRequest()
             ->resetResponse();

         // test that id must be unique (can't add same category twice).
        $this->request->setMethod('POST');
        $this->request->setPost('title',       $title);
        $this->request->setPost('parent',      '');
        $this->request->setPost('description', $description);
        $this->request->setPost(P4Cms_Form::CSRF_TOKEN_NAME, P4Cms_Form::getCsrfToken());
        $this->dispatch('/category/manage/add');
        $this->assertQueryCount('ul.errors', 1, 'Expected id error.');

        $this->resetRequest()
             ->resetResponse();

        // test that the added category appears as a parent
        $this->dispatch('/category/manage/add');
        $this->assertModule('category', 'Expected module.');
        $this->assertController('manage', 'Expected controller');
        $this->assertAction('add', 'Expected action');

        $this->assertQueryContentContains('option', $title);
    }
Category_Test_ManageControllerTest::testGoodEditPost ( )

Test good post to edit.

    {
        $this->utility->impersonate('editor');

        // create category to be edited.
        Category_Model_Category::store(array('id' => 'edit-me', 'title' => 'Edit Me'));
        Category_Model_Category::store(array('id' => 'edit-me/subcat', 'title' => 'subCat', 'description' => 'docs'));

        // form request without required fields.
        $this->request->setParam('category', 'edit-me/subcat');
        $this->request->setMethod('POST');
        $this->request->setPost('title',       'Test Category');
        $this->request->setPost('parent',      'edit-me');
        $this->request->setPost('description', 'new docs');
        $this->request->setPost(P4Cms_Form::CSRF_TOKEN_NAME, P4Cms_Form::getCsrfToken());

        $this->dispatch('/category/manage/edit');
        $this->assertModule('category', 'Expected module.');
        $this->assertController('manage', 'Expected controller');
        $this->assertAction('edit', 'Expected action');

        // check for saved category entry.
        $this->assertTrue(
            Category_Model_Category::exists('edit-me/test-category'),
            'Expected edited category to be saved.'
        );
        $this->assertFalse(
            Category_Model_Category::exists('edit-me/subcat'),
            'Expected original category to be gone.'
        );
        $category = Category_Model_Category::fetch('edit-me/test-category');
        $this->assertSame(
            'Test Category',
            $category->getValue('title'),
            "Expected same title as was posted."
        );
        $this->assertSame(
            'new docs',
            $category->getValue('description'),
            "Expected same description as was posted."
        );
    }
Category_Test_ManageControllerTest::testIndex ( )

Test the index action.

    {
        $this->utility->impersonate('editor');

        $this->dispatch('/category/manage/index');
        $this->assertModule('category', 'Expected module.');
        $this->assertController('manage', 'Expected controller');
        $this->assertAction('index', 'Expected 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.category.grid.instance"]',
            'Expected dojox.grid table'
        );

        // verify add button appears
        $this->assertXpath('//button[@class="add-button"]', 'Expected category add link.');

        // create several categories.
        $items = array();
        for ($i = 1; $i <= 10; $i++) {
            $values = array(
                'id'            => "test-cat-$i",
                'title'         => "Test Category $i",
                'description'   => "a category for testing #$i",
            );
            Category_Model_Category::store($values);
            $items[] = $values;
        }

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

        $data = Zend_Json::decode($body);

        // verify number of items
        $this->assertSame(
            count($items),
            $data['numRows'],
            'Expected number of items'
        );

        // verify item values
        reset($items);
        foreach ($data['items'] as $item) {
            $this->assertSame(
                current($items),
                array_intersect($item, current($items)),
                'Expected item values'
            );
            next($items);
        }
    }

The documentation for this class was generated from the following file: