$user->name, 'points' => $points, ); $this->drupalPost('admin/config/people/userpoints/add', $edit, t('Save')); if ($total !== NULL) { $categories = userpoints_get_categories(); $tid = userpoints_get_default_tid(); $category = $categories[$tid]; $this->assertText(t('@name just earned @points points and now has @total points in the @category category.', array('@name' => $user->name, '@points' => $points, '@total' => $total, '@category' => $category)), t('Correct confirmation message displayed.')); $this->assertEqual($total, userpoints_get_current_points($user->uid, $tid), t('User has the correct total amount of points.')); } return db_query('SELECT MAX(txn_id) FROM {userpoints_txn} WHERE uid = :uid', array(':uid' => $user->uid))->fetchField(); } /** * Verify the current and optionally max points in a specific category. * * @param $uid * User uid for the user that needs to be tested. * @param $current * The amount of points the user is currently supposed to have. * @param $max * The amount of max points of the user. Only tested if not NULL. * @param $tid * The category that needs to be checked. Default is used is none is * provided. */ function verifyPoints($uid, $current, $max = NULL, $tid = NULL) { // Check if a term id is passed as a parameter. if (!$tid) { // It is not, so get the default term id. $tid = userpoints_get_default_tid(); } debug('Current is: ' . userpoints_get_current_points($uid, $tid) . ', should be: ' . $current); $this->assertEqual($current, userpoints_get_current_points($uid, $tid), t('Current points are correct.')); if ($max !== NULL) { // Hijack static cache, delete this item from it. $max_cache = &drupal_static('userpoints_get_max_points', array()); unset($max_cache[$uid][$tid]); debug('Max is: ' . userpoints_get_max_points($uid, $tid) . ', should be: ' . $max); $this->assertEqual($max, userpoints_get_max_points($uid, $tid), t('Max points are correct.')); } } } /** * API Tests. */ class UserpointsAPITestCase extends UserpointsBaseTestCase { private $admin_user; private $non_admin_user; /** * Implements getInfo(). */ function getInfo() { return array( 'name' => t('Userpoints API'), 'description' => t('Tests the core API for proper inserts & updates to the database tables, moderation, expiration, as well as permission checks'), 'group' => t('Userpoints'), ); } /** * Install userpoints module and create users. */ function setUp() { parent::setUp('userpoints'); // Create an administrator account. $this->admin_user = $this->drupalCreateUser(array('administer userpoints')); // Create a standard Drupal account and log in as that person. $this->non_admin_user = $this->drupalCreateUser(); $this->drupalLogin($this->non_admin_user); } /** * Returns the user points of a specific transaction. * * @param $uid * User uid for which the points should be selected. * @param $points * Optionaly define which transaction should be loaded by specifying the * points. * @param $sum * If TRUE, calculate the sum of all matching transaction rows. * @return * Amount of points according to the arguments. */ function getTxnPoints($uid, $points = NULL, $sum = FALSE) { $query = db_select('userpoints_txn', 'p'); if ($sum) { $query->addExpression('SUM(points)'); } else { $query->addField('p', 'points'); } $query->condition('uid', $uid); if ($points) { $query->condition('points', $points); } return (int)$query->execute()->fetchField(); } /** * Returns the user points. * * @param $uid * User uid for which the points should be selected. * @param $points * Optionaly define which transaction should be loaded by specifying the * points. * @param $sum * If TRUE, calculate the sum of all matching transaction rows. * @return * Amount of points according to the arguments. */ function getPoints($uid, $points = NULL, $sum = FALSE) { $query = db_select('userpoints', 'p'); if ($sum) { $query->addExpression('SUM(points)'); } else { $query->addField('p', 'points'); } $query->condition('uid', $uid); if ($points) { $query->condition('points', $points); } return (int) $query->execute()->fetchField(); } /** * Call userpoints_userpointsapi() with just points. */ function testBasicCall() { global $user; $points = (int) rand(1, 500); $sumpoints = $points; // NOTE: increment max points with all positive point changes, tests userpoints_get_max_points. $maxpoints = $points; // Test the a basic API call. $return = userpoints_userpointsapi($points); $this->assertTrue($return['status'] == TRUE, t('API responded with successful grant of points')); // Check the database to ensure the point were properly saved. $this->assertTrue($this->getTxnPoints($user->uid, $points) === $points, t('Successfully verified points in the txn table')); // Check that the transaction table and the summary table match. $this->assertTrue($this->getTxnPoints($user->uid, NULL, TRUE) === $this->getPoints($user->uid, NULL, TRUE), t('Sum of transactions match total points for user')); // Add negative points to the initial value and check the values. $points = -rand(1, 500); $sumpoints = $sumpoints + $points; userpoints_userpointsapi($points); // Check the database to ensure the negative point value was properly saved. $this->assertTrue($this->getTxnPoints($user->uid, $points) === $points, t('Successfully verified negative points in the txn table')); // Now test to make sure the transaction and and caching table stay in sync. // Also test userpoints_get_max_points and userpoints_get_current_points. for ($i = 0; $i <= rand(1, 50); $i++) { $points = rand(1, 500); if (rand() & 1) { $points = - $points; } $sumpoints = $sumpoints + $points; if ($sumpoints > $maxpoints) { $maxpoints = $sumpoints; } userpoints_userpointsapi($points); } // Check the summary table to make sure everything is still kosher. $this->assertEqual($this->getTxnPoints($user->uid, NULL, TRUE), $this->getPoints($user->uid, NULL, TRUE)); $this->assertEqual($this->getPoints($user->uid, NULL, TRUE), $sumpoints); $this->assertEqual($sumpoints, userpoints_get_current_points()); $this->assertEqual($maxpoints, userpoints_get_max_points()); } /** * Call the api functions with an array. */ function testParamsArrayCall() { $points = rand(); // Assert that the use of a params array with simply points in it works. $params = array( 'points' => $points, 'uid' => $this->non_admin_user->uid, ); $this->assertTrue(userpoints_userpointsapi($params) == TRUE, t('API call using a params array responded with successful grant of points') ); // Check the Database to make sure the points made it there. $this->assertTrue($this->getPoints($this->non_admin_user->uid, NULL, TRUE) == $points, t('Successfully verified points in the txn table')); // Test to ensure that calling it with no points returns FALSE indicating an error. $params = array( 'points' => '', 'uid' => $this->non_admin_user->uid, ); $return = userpoints_userpointsapi($params); $this->assertFalse($return['status'], t('API successfully prevented null points from being added')); $params = array( 'points' => 'abcd', 'uid' => $this->non_admin_user->uid, ); $return = userpoints_userpointsapi($params); $this->assertFalse($return['status'], t('API successfully prevented non-numeric points from being added')); // Award points to admin user and test to ensure they were awarded to the correct user. $params = array( 'points' => $points, 'uid' => $this->admin_user->uid, ); $this->assertTrue(userpoints_userpointsapi($params) == TRUE, t('Successfully granted points to admin user')); // Check the Database to make sure the points made it there. $this->assertTrue($this->getPoints($this->non_admin_user->uid, NULL, TRUE) == $points, t('Successfully verified points in the txn table')); // Attempt to award points to a non-existent user. $sql = "SELECT MAX(uid) FROM {users}"; $nonuid = db_query($sql)->fetchField() + 1; $params = array( 'points' => $points, 'uid' => $nonuid, ); $ret = userpoints_userpointsapi($params); $this->assertFalse($ret['status'], t('Successfully blocked points given to a non-existent user')); /** * @todo: This is not actually implemented, just passed the tests because it * has set the 'uid' key instead of 'tid'. // Attempt to award points to a non-existent term. $maxtid = "SELECT MAX(tid) from {taxonomy_term_data}"; $nontid = db_query($sql)->fetchField() + 1; $params = array( 'points' => $points, 'tid' => $nontid, ); $ret = userpoints_userpointsapi($params); $this->assertFalse($ret['status'], t('Successfully blocked points given to a non-existent tid')); */ // Test various aspects of the API to ensure the DB is being updated successfully. $points = rand(1, 500); $description = $this->randomName(); $operation = $this->randomName(); $params = array( 'points' => $points, 'description' => $description, 'operation' => $operation, ); $ret = userpoints_userpointsapi($params); $sql = "SELECT description, operation, reference FROM {userpoints_txn} WHERE description = :description AND operation = :operation"; $db_point_rec = db_query($sql, array(':description' => $description, ':operation' => $operation))->fetchAssoc(); $this->assertTrue($db_point_rec['description'] == $description, t('Point description successfully verified in DB')); $this->assertTrue($db_point_rec['operation'] == $operation, t('Point event successfully verified in DB')); } function testExpiration() { $points = rand(1, 100); $sum_points = 0; // Create various time tests. $times['valid']['time'] = rand(1, 10000); $times['valid']['string'] = '(expirydate = random number)'; $times['expire']['time'] = REQUEST_TIME; $times['expire']['string'] = '(expirydate = today)'; $times['null']['time'] = NULL; $times['null']['string'] = '(expirydate = NULL)'; $bad_time = 'test string'; // First lets check to make sure it is blocking bad times. $params = array( 'uid' => $this->non_admin_user->uid, 'points' => $points, 'expirydate' => $bad_time, ); $return = userpoints_userpointsapi($params); $this->assertFalse($return['status'], t(print_r($return, TRUE) . "API succesfully blocked an entry with a string as the expiry date")); foreach ($times as $time) { $params = array( 'uid' => $this->non_admin_user->uid, 'points' => $points, 'expirydate' => $time['time'], ); $return = userpoints_userpointsapi($params); $this->assertTrue($return['status'], t($time['string'] . " API responded with a successful grant of points")); // Check the database to ensure the points were properly saved. $sql = "SELECT points FROM {userpoints_txn} WHERE uid = :uid AND points = :points AND expirydate = :date"; $db_points = (int) db_query($sql, array(':uid' => $this->non_admin_user->uid, ':points' => $points, ':date' => (int) $time['time']))->fetchField(); $this->assertEqual($db_points, $points, t($time['string'] . "Successfully verified points in the txn table.")); if ($db_points == $points) { $sum_points = $sum_points + $points; } // Check update point to 'userpoints' table. $this->assertEqual($this->getPoints($this->non_admin_user->uid), $sum_points, t($time['string'] . "Successfully verified that the summary table was updated")); } // Clear the slate again. db_truncate('userpoints') ->execute(); db_truncate('userpoints_txn') ->execute(); // Set a default expire time. variable_set(USERPOINTS_EXPIREON_DATE, REQUEST_TIME + 5000); // Add two different points in, one to post immediately another to expire in the future. $keep_points = rand(1, 100); $expire_points = rand(1, 100); $params = array( 'uid' => $this->non_admin_user->uid, 'points' => $expire_points, 'expirydate' => REQUEST_TIME - 1000, 'operation' => 'must_expire', ); $return = userpoints_userpointsapi($params); $this->assertTrue($return['status'], t("API succesfully added points for expiration")); $params = array( 'uid' => $this->non_admin_user->uid, 'points' => $keep_points, 'expirydate' => REQUEST_TIME + 10000, 'operation' => 'must_not_expire', ); userpoints_userpointsapi($params); $this->assertTrue($return['status'], t("API succesfully added points for expiration")); // Load timestamp of the first transaction. $time_stamp = db_query('SELECT time_stamp FROM {userpoints_txn} WHERE operation = :op', array(':op' => 'must_expire'))->fetchField(); // Call cron to check expiration. drupal_cron_run(); // Check the user points removed or not if the point was expiration. $this->assertEqual($this->getTxnPoints($this->non_admin_user->uid, NULL, TRUE), $keep_points, t("Successfully removed expired points from the txn table.")); $this->assertEqual($this->getPoints($this->non_admin_user->uid), $keep_points, t("Successfully removed expired points from the summary table.")); // Load the expiry transaction from the database and verify that it does // not expire. $expired_time = db_query('SELECT expirydate FROM {userpoints_txn} WHERE operation = :expiry', array(':expiry' => 'expiry'))->fetchField(); $this->assertEqual($expired_time, 0, t('Expiry userpoints transaction does not expire.')); // Load expired transaction and verify that time_stamp was not updated. $updated_time_stamp = db_query('SELECT time_stamp FROM {userpoints_txn} WHERE expired = 1')->fetchField(); $this->assertEqual($time_stamp, $updated_time_stamp, t('Time stamp of expired transaction was not changed.')); } /** * Changes the default expiration date in the administrative settings * and then checks to ensure that it is saved/returned correctly. */ function testDefaultExpireDate() { // Login as an admin. $this->drupalLogin($this->admin_user); // Use a date in the future. $date = REQUEST_TIME + 100000; $date_array = array( 'month' => date('n', $date), 'day' => date('d', $date), 'year' => date('Y', $date), ); // save settings. $edit = array( 'userpoints_expireon_date[month]' => $date_array['month'], 'userpoints_expireon_date[day]' => $date_array['day'], 'userpoints_expireon_date[year]' => $date_array['year'], ); $this->drupalPost('admin/config/people/userpoints/settings', $edit, 'Save configuration'); // Check database. $database_date = variable_get('userpoints_expireon_date', FALSE); $this->assertEqual($database_date['day'], $date_array['day']); $this->assertEqual($database_date['month'], $date_array['month']); $this->assertEqual($database_date['year'], $date_array['year']); // Check API. $expiry_date = userpoints_get_default_expiry_date(); $this->assertEqual($expiry_date, userpoints_date_to_timestamp($date_array)); } /** * Test the default term id. */ function testGetDefaultTid() { $vid = userpoints_get_vid(); $term_name = $this->randomName(10); $desc = $this->randomName(10); // create a new term. $term = (object) array( 'name' => $term_name, 'description' => $desc, 'vid' => $vid ); taxonomy_term_save($term); // login as admin userpoints $this->admin_user = $this->drupalCreateUser(array('administer userpoints')); $this->drupalLogin($this->admin_user); // save settings. $edit = array( 'userpoints_category_default_tid' => $term->tid, ); $this->drupalPost('admin/config/people/userpoints/settings', $edit, 'Save configuration'); // Check database. $this->assertEqual(variable_get('userpoints_category_default_tid', FALSE), $term->tid); // check API. $tid = userpoints_get_default_tid(); $this->assertEqual($tid, $term->tid); // Check database. $this->assertTrue(variable_get('userpoints_category_default_vid', FALSE) != FALSE, t("Successfully verified the vocab ID in the database.")); // Check API. $vid = userpoints_get_vid(); $this->assertTrue(is_numeric($vid), t("Successfully retrieved default vid %d.", array('%d' => $vid))); } /** * Test user permissions */ function testUserpermissions() { $this->non_admin_username = 'test'; $points = 10; // check permission with admin user. $this->admin_user = $this->drupalCreateUser(array('administer userpoints')); $this->drupalLogin($this->admin_user); // check access page. $this->drupalGet('admin/config/people/userpoints'); $content = $this->drupalGetContent(); $content = strstr($content, 'Access denied'); $this->assertTrue($content == FALSE, t("Successful navigated to the page modify points")); // check modify points. $edit = array( 'txn_user' => $this->admin_user->name, 'points' => $points, ); $this->drupalPost('admin/config/people/userpoints/add', $edit, 'Save'); // Check database. $this->assertEqual($this->getTxnPoints($this->admin_user->uid, $points), $points, t("Successful verified that points were added into database.")); // logout and change user. $this->drupalLogout(); // check permission with view user. $view_user = $this->drupalCreateUser(array('view userpoints')); $this->drupalLogin($view_user); // check access page. $this->drupalGet('admin/config/people/userpoints'); $this->assertResponse(403, t("Successful verified that a user without admin userpoints permissions can not access the admin interface.")); } function testModeration() { $points = rand(1, 100); // condition1 moderate=TRUE. $params = array( 'uid' => $this->non_admin_user->uid, 'points' => $points, 'moderate' => TRUE, ); // add points to user. $return = userpoints_userpointsapi($params); $this->assertTrue($return['status'] == TRUE, t("1. (moderate=TRUE) API responded with successful grant of points")); // Check the database to ensure the point were properly saved. $this->assertTrue($this->getTxnPoints($this->non_admin_user->uid, $points) == $points, t("1. (moderate=TRUE) Successfully verified points in the txn table and waiting moderation.")); // Check do not update point to 'userpoints' table. $this->assertTrue($this->getPoints($this->non_admin_user->uid) == 0, t("1. (moderate=TRUE) Successfully verified that points were added and the summary table was not updated.")); /* //DISABLED because it should be checking if it adhered to the sites default moderation status $params = array ( 'uid' => $this->non_admin_user->uid, 'points' => $points, 'moderate' => NULL, ); $return = userpoints_userpointsapi($params); $this->assertTrue($return['status'] == TRUE , t("6. (moderate=NULL) API responded with successful grant of points")); $sql = "SELECT points FROM {userpoints_txn} WHERE uid = %d AND points = %d AND status = 1"; $db_points = (int) db_result(db_query($sql, $this->non_admin_user->uid, $points)); $this->assertTrue($db_points == $points,t("6. (moderate=NULL) Successfully verified points in the txn table and waiting moder.") ); $sql1 = "SELECT points FROM {userpoints} WHERE uid=%d"; $db_points = (int) db_result(db_query($sql1, $this->non_admin_user->uid)); $this->assertTrue($db_points == 0,t("6. (moderate=NULL) Successfully, Points added and does not modify summary table.") ); */ // condition7 moderate=FALSE. $params = array( 'uid' => $this->non_admin_user->uid, 'points' => $points, 'moderate' => FALSE, ); // add points to user. $return = userpoints_userpointsapi($params); $this->assertTrue($return['status'] == TRUE, t("7. (moderate=FALSE) API responded with successful grant of points")); // Check the database to ensure the point were properly saved. $sql = "SELECT points FROM {userpoints_txn} WHERE uid = :uid AND points = :points AND status = 0"; $db_points = (int) db_query($sql, array(':uid' => $this->non_admin_user->uid, ':points' => $points))->fetchField(); $this->assertTrue($db_points == $points, t("7. (moderate=FALSE) Successfully verified points in the txn table and NOT waiting moderation.")); } /** * Tests the userpoints_get_categories() function. */ function testGetCategories() { $cats = userpoints_get_categories(); $this->assertTrue(is_array($cats), 'Successfully verified userpoints_get_categories() returned an array'); } /** * Test that editing points correctly updates the current and max points. */ function testEditingTransactions() { // First, add some points to two different categories. $uid = $this->non_admin_user->uid; $params = array( 'points' => 100, 'tid' => 0, 'uid' => $uid, ); userpoints_userpointsapi($params); $params = array( 'points' => 50, 'tid' => 1, 'uid' => $uid, ); userpoints_userpointsapi($params); // Add a third transaction that can be edited. $params = array( 'points' => 5, 'tid' => 0, 'uid' => $uid, ); $return = userpoints_userpointsapi($params); $txn_id = $return['transaction']['txn_id']; // Verify points up to this point. $this->verifyPoints($uid, 105, 105, 0); $this->verifyPoints($uid, 50, 50, 1); // Now, edit the transaction. Mix any combination of point, category and // status changes. After the change, verify current and max points. // Points change. $params = array( 'txn_id' => $txn_id, 'points' => -5, ); userpoints_userpointsapi($params); $this->verifyPoints($uid, 95, 105, 0); // Change status to pending. $params = array( 'txn_id' => $txn_id, 'status' => USERPOINTS_TXN_STATUS_PENDING, ); userpoints_userpointsapi($params); $this->verifyPoints($uid, 100, 105, 0); // Change status back to approved. $params = array( 'txn_id' => $txn_id, 'status' => USERPOINTS_TXN_STATUS_APPROVED, ); userpoints_userpointsapi($params); $this->verifyPoints($uid, 95, 105, 0); // Change category. $params = array( 'txn_id' => $txn_id, 'tid' => 1, ); userpoints_userpointsapi($params); $this->verifyPoints($uid, 100, 105, 0); $this->verifyPoints($uid, 45, 50, 1); // Change points and status. $params = array( 'txn_id' => $txn_id, 'points' => 3, 'status' => USERPOINTS_TXN_STATUS_PENDING, ); userpoints_userpointsapi($params); $this->verifyPoints($uid, 100, 105, 0); $this->verifyPoints($uid, 50, 50, 1); // Change status back to approved. $params = array( 'txn_id' => $txn_id, 'status' => USERPOINTS_TXN_STATUS_APPROVED, ); userpoints_userpointsapi($params); $this->verifyPoints($uid, 53, 53, 1); // Change points and category. $params = array( 'txn_id' => $txn_id, 'points' => 4, 'tid' => 0, ); userpoints_userpointsapi($params); $this->verifyPoints($uid, 104, 105, 0); $this->verifyPoints($uid, 50, 53, 1); // Change points and status and category. $params = array( 'txn_id' => $txn_id, 'points' => 10, 'tid' => 1, 'status' => USERPOINTS_TXN_STATUS_DECLINED, ); userpoints_userpointsapi($params); $this->verifyPoints($uid, 100, 105, 0); $this->verifyPoints($uid, 50, 53, 1); // Change points and status back to approved. $params = array( 'txn_id' => $txn_id, 'points' => 9, 'status' => USERPOINTS_TXN_STATUS_APPROVED, ); userpoints_userpointsapi($params); $this->verifyPoints($uid, 59, 59, 1); $this->verifyPoints($uid, 159, 164, 'all'); } } /** * Administration UI tests */ class UserpointsAdminTestCase extends UserpointsBaseTestCase { private $admin_user; private $non_admin_user; /** * Implements getInfo(). */ function getInfo() { return array( 'name' => t('Userpoints Admin'), 'description' => t('Test various userpoints administration forms and listings.'), 'group' => t('Userpoints'), ); } /** * Install userpoints module and create users. */ function setUp() { parent::setUp('userpoints'); // Create an administrator account and log in with that. $this->admin_user = $this->drupalCreateUser(array('administer userpoints')); $this->drupalLogin($this->admin_user); } function testAddEditPoints() { $user = $this->drupalCreateUser(); $categories = userpoints_get_categories(); $tid = userpoints_get_default_tid(); $category = $categories[$tid]; // Grant some points with admin user. $txn_id = $this->addPoints(10, $user, 10); // Go to the listing page, verify that the user is shown. $row = $this->xpath('//table/tbody/tr'); //$this->assertEqual(strip_tags((string)$row[0]->td[0]), t('@name (details)', array('@name' => $user->name)), t('User name with details link displayed.')); $this->assertEqual((string)$row[0]->td[1], $category, t('Category correctly displayed.')); $this->assertEqual((string)$row[0]->td[2], 10, t('Points correctly displayed.')); // Go to the transaction listing page, verify that the transaction is shown. $this->clickLink(t('Transactions')); $row = $this->xpath('//table/tbody/tr'); $transaction = userpoints_transaction_load($txn_id); $this->assertEqual((string)$row[0]->td[0], 10, t('Points correctly displayed.')); //$this->assertEqual(strip_tags((string)$row[0]->td[1]), $user->name, t('User correctly displayed.')); $this->assertEqual((string)$row[0]->td[2], format_date($transaction->time_stamp, 'small'), t('Date correctly displayed.')); $this->assertEqual((string)$row[0]->td[3], 'admin', t('Reason correctly displayed.')); $this->assertEqual((string)$row[0]->td[4], t('Approved'), t('Status correctly displayed.')); $this->clickLink(t('edit')); // Verify default values. $this->assertFieldByName('points', 10); $value = $this->xpath("//input[@name=:name and @disabled=:disabled]/@value", array(':name' => 'txn_user', ':disabled' => 'disabled')); $this->assertEqual($value[0]['value'], $user->name, t('User field has the correct value and is disabled.')); $this->assertFieldByName('approver', $this->admin_user->name); $edit = array( 'points' => 7, 'operation' => $this->randomName(), 'description' => $this->randomName(), 'reference' => $this->randomName(), ); $this->drupalPost(NULL, $edit, t('Save')); // Verify that the transaction has been updated. $this->assertEqual(7, userpoints_get_current_points($user->uid)); $row = $this->xpath('//table/tbody/tr'); $transaction = userpoints_transaction_load($transaction->txn_id); $this->assertEqual((string)$row[0]->td[0], 7, t('Points correctly displayed.')); //$this->assertEqual(strip_tags((string)$row[0]->td[1]), $user->name, t('User correctly displayed.')); $this->assertEqual((string)$row[0]->td[2], format_date($transaction->time_stamp, 'small'), t('Date correctly displayed.')); $this->assertEqual((string)$row[0]->td[3], $edit['description'], t('Reason correctly displayed.')); $this->assertEqual((string)$row[0]->td[4], t('Approved'), t('Status correctly displayed.')); // Go to the listing page, verify that the total points have been updated. $this->clickLink(t('Totals')); $row = $this->xpath('//table/tbody/tr'); //$this->assertEqual(strip_tags((string)$row[0]->td[0]), t('@name (details)', array('@name' => $user->name)), t('User name with details link displayed.')); $this->assertEqual((string)$row[0]->td[1], $category, t('Category correctly displayed.')); $this->assertEqual((string)$row[0]->td[2], 7, t('Points correctly displayed.')); // View transaction details. $this->clickLink(t('Transactions')); $this->clickLink('view'); } }