{"id":23412522,"url":"https://github.com/gocodebox/lifterlms-tests","last_synced_at":"2025-10-28T22:18:17.804Z","repository":{"id":33440554,"uuid":"158437397","full_name":"gocodebox/lifterlms-tests","owner":"gocodebox","description":"LifterLMS Tests is a project to help bootstrap automated testsing in LifterLMS projects.","archived":false,"fork":false,"pushed_at":"2025-04-04T00:06:41.000Z","size":223,"stargazers_count":2,"open_issues_count":2,"forks_count":2,"subscribers_count":3,"default_branch":"trunk","last_synced_at":"2025-04-04T01:19:46.499Z","etag":null,"topics":["elearning","hacktoberfest","lifterlms","lms","php","phpunit"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gocodebox.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-20T18:58:39.000Z","updated_at":"2025-04-04T00:06:36.000Z","dependencies_parsed_at":"2023-01-15T00:55:33.434Z","dependency_job_id":"bd62f78d-0f91-4c74-b8ea-39007b139940","html_url":"https://github.com/gocodebox/lifterlms-tests","commit_stats":{"total_commits":154,"total_committers":7,"mean_commits":22.0,"dds":"0.24025974025974028","last_synced_commit":"1b6105ec6ec39146bc9155d654e3dead67abf97d"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gocodebox%2Flifterlms-tests","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gocodebox%2Flifterlms-tests/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gocodebox%2Flifterlms-tests/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gocodebox%2Flifterlms-tests/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gocodebox","download_url":"https://codeload.github.com/gocodebox/lifterlms-tests/tar.gz/refs/heads/trunk","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248514221,"owners_count":21116899,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elearning","hacktoberfest","lifterlms","lms","php","phpunit"],"created_at":"2024-12-22T18:16:15.172Z","updated_at":"2025-10-28T22:18:17.727Z","avatar_url":"https://github.com/gocodebox.png","language":"PHP","readme":"LifterLMS Tests\n===============\n\nLifterLMS Tests is a project to help bootstrap automated testing in LifterLMS projects.\n\n## Installation\n\n+ Install package: `composer require --dev lifterlms/lifterlms-tests`\n+ Create a `phpunit.xml.dist` file. See [example](examples/phpunit.xml.dist).\n+ Add a `tests` direcotry: `mkdir tests`\n+ Create a bootstrap file in the `tests` directory. see [example](examples/bootstrap.php).\n+ Add test classes in `tests/unit-tests`\n\n## Commands\n\n+ Install Testing Suite: `./vendor/bin/llms-tests install \u003cdb-name\u003e \u003cdb-user\u003e \u003cdb-pass\u003e [db-host] [wp-version] [skip-database-creation]`\n+ Teardown Testing Suite: `.vendor/bin/llms-tests teardown \u003cdb-name\u003e \u003cdb-user\u003e \u003cdb-pass\u003e [db-host]`\n+ Install a Plugin: `./vendor/bin/llms-tests plugin \u003cslug_or_zip_giturl\u003e [version]`\n+ Run tests: `./vendor/bin/phpunit`\n+ Environment: `./vendor/bin/llms-env \u003ccommand\u003e [options]`. See `./vendor/bin/llms-env --help` for full documentation.\n\n## Environment\n\nThe `llms-env` command provides a simple set of tools helpful in managing a set of Docker containers for use in development and testing of a LifterLMS plugin.\n\nFor customization, run `llms-env config` to create the recommended `docker-compose.yml` and `.llmsenv` files in the project root.\n\nThe `docker-compose.yml` will automatically mount the root directory into the `wp-content/plugin` directory.\n\nThe `.llmsenv` file allows customization of the WordPress username, localhost port, and more. This file is optional and the defaults will be used if any variables are excluded.\n\nAfter setting up the configuration files run `llms-env up` to create the containers, install, and configure WordPress.\n\nIf any additional plugins are required or any other WordPress configurations are required, try creating a composer script that runs the required commands via `wp-cli` on the main PHP service container. For example, add a script in your composer.json:\n\n```json\n{\n  \"scripts\": {\n    \"env-setup\": [\n      \"./vendor/bin/llms-env wp plugin install lifterlms --activate\"\n    ]\n  }\n}\n```\n\nThis can be run to activate the LifterLMS core.\n\nThe `llms-env` provides many commands for composing and managing the Docker containers. Run `llms-env --help` for a full list of available commands as well as information on their usage.\n\n\n## Predefined scripts\n\nThe following scripts can be added to your `composer.json` file for easy access to thes scripts \u0026 to ensure configurations are automatically set during package installation and updates.\n\n```json\n\"scripts\": {\n    \"tests-install\": [\n      \"vendor/bin/llms-tests teardown llms_tests root password localhost\",\n      \"vendor/bin/llms-tests install llms_tests root password localhost\",\n      \"vendor/bin/llms-tests plugin lifterlms\"\n    ],\n    \"tests-run\": [\n      \"vendor/bin/phpunit\"\n    ]\n}\n```\n\n## Utilities\n\nUtility methods are located in the `LLMS_Unit_Test_Util` class.\n\nRetrieve a private/protected class method:\n\n```php\n$method = LLMS_Unit_Test_Util::get_private_method( new MyClass(), 'my_private_method' );\n$method = LLMS_Unit_Test_Util::get_protected_method( new MyClass(), 'my_private_method' );\n```\n\nCall a private/protected class method for testing:\n\n```php\n$result = LLMS_Unit_Test_Util::call_method( new MyClass(), 'my_private_method', array( 'argument_1', 'arg_2', ... ) );\n$this-\u003eassertTrue( $result );\n```\n\n## Functions\n\nMock the return of `llms_current_time()` by using `llms_tests_mock_current_time( $timestamp_or_date )`\n\nReset the current time with `llms_tests_reset_current_time()`\n\n\n## Test Case Methods\n\nTest cases which extend the `LLMS_Unit_Test_Case` class may access utility functiosn built into the test case class.\n\n##### Assertions\n\nTest cases which extend the `LLMS_Unit_Test_Case` class may access utility functiosn built into the test case class.\n\n###### Assets\n\nAssert that assets (scripts or styles) are registered or enqueued (or inversely not registered or not enqueued) with WordPress dependency managements classes.\n\n`$type` is either \"script\" or \"style\" and `$handle` is the asset handle used to register/enqueue the script.\n\n+ Assert a script/style is registered: `$this-\u003eassertAssetIsRegistered( $type, $handle )`\n+ Assert a script/style is not registered: `$this-\u003eassertAssetNotRegistered( $type, $handle )`\n+ Assert a script/style is enqueued: `$this-\u003eassertAssetIsEnqueued( $type, $handle )`\n+ Assert a script/style is not enqueued: `$this-\u003eassertAssetNotEnqueued( $type, $handle )`\n\n###### Output Buffering\n\n+ Assert the output of a function contains a string: `$this-\u003eassertOutputContains( $contains, $callable, $args_array );`\n+ Assert the output of a function does not contain a string: `$this-\u003eassertOutputNotContains( $contains, $callable, $args_array );`\n+ Assert the output of a function is empty: `$this-\u003eassertOutputEmpty( $callable, $args_array );`\n+ Assert the output of a function equals an expectation: `$this-\u003eassertOutputEquals( $expected, $callable, $args_array );`\n\n###### `WP_Error`\n\n+ Assert an object is a `WP_Error`:  `$this-\u003eassertWPError( $wp_err );`\n+ Assert a `WP_Error` code equals an expectation: `$this-\u003eassertWPErrorCodeEquals( $code, $wp_err );`\n+ Assert a `WP_Error` message equals an expectation: `$this-\u003eassertWPErrorMessageEquals( $message, $wp_err );`\n+ Assert a `WP_Error` data equals an expectation: `$this-\u003eassertWPErrorDataEquals( $data, $wp_err );`\n\n\n##### Mock `$_GET`, `$_POST`, and `$_REQUEST` data\n\nAdd mock `$_GET` data via `$this-\u003emockGetRequest( array( 'var' =\u003e 'value' ) );`\n\nAdd mock `$_POST` data via `$this-\u003emockPostRequest( array( 'var' =\u003e 'value' ) );`\n\n\n##### Mock HTTP request made via `wp_remote_request()`.\n\nBefore calling `wp_remote_request()` run `$this-\u003emock_http_request( $url, $data, $fuzzy_match )` to setup the desired return of the next `wp_remote_request()`.\n\nWhen `wp_remote_request()` is run, the mocker will check to see if a mock has been added for the URL, if found, it will short-circuit the HTTP request and return early (before any remote connection is made), returning the value of `$data`. Once the mock is found and returned, it will be removed from the mocker's data. If you wish to mock several consecutive URLs you can call `mock_http_request()` multiple times. The matcher will always return the *first* match. So if you wish to mock the same URL more than once, make sure setup the mocks in the order you expect them to be returned.\n\nYou can specify a full or partial URL as the `$url` parameter. If a specifying a partial URL, use `$fuzzy_match = true` to match the URL part.\n\n```php\n\npublic function test_mock_https_request() {\n\n  // Mocks a WP REST post creation request.\n  $this-\u003emock_http_request( '/wp-json/wp/v2/posts',\n    [ \n      'body'     =\u003e '{\"id\":123,\"title\":\"Mock Title\",...}',\n      'response' =\u003e [\n        'code' =\u003e 201,\n      ],\n    ], \n    true\n  );\n\n  $res = wp_remote_post( \n    rest_url( '/wp-json/wp/v2/posts' ),\n    [\n      'body' =\u003e [\n        'title' =\u003e 'Mock Title',\n      ],\n    ],\n  );\n\n  $this-\u003eassertEquals( 201, wp_remote_retrieve_response_code( $res ) );\n  $this-\u003eassertEquals( 123, json_decode( wp_remote_retrieve_response_body( $res ) )['id'] );\n\n}\n\n\n##### Utility Methods\n\n+ Get the output of a function: `$output = $this-\u003eget_output( $callable, $args_array );`\n\n## Exceptions\n\nIncluded exceptions allow easy testing of methods which call `exit()` and `llms_redirect_and_exit()`.\n\n##### LLMS_Unit_Test_Exception_Exit\n\nTest methods which call `exit()`: Call `$this-\u003eexpectException( LLMS_Unit_Test_Exception_Exit::class );` before calling the function that calls exit.\n\n```php\npublic function test_example_exit() {\n  $this-\u003eexpectException( LLMS_Unit_Test_Exception_Exit::class );\n  example_function_that_exits();\n}\n```\n\n##### LLMS_Unit_Test_Exception_Redirect\n\nTest methods which call `llms_redirect_and_exit()`:\n\n```php\npublic function test_my_redirect_and_exit() {\n  $this-\u003eexpectException( LLMS_Unit_Test_Exception_Redirect::class );\n  $this-\u003eexpectExceptionMessage( 'https://lifterlms.com [302] YES' );\n  llms_redirect_and_exit( 'https://lifterlms.com' );\n}\n```\n\nThe exceptions will cause PHP execution to cease. To run additional tests after the exception is encountered add a try/catch block:\n\n```php\npublic function test_my_redirect_and_exit() {\n  $this-\u003eexpectException( LLMS_Unit_Test_Exception_Redirect::class );\n  $this-\u003eexpectExceptionMessage( 'https://lifterlms.com [302] YES' );\n  try {\n    llms_redirect_and_exit( 'https://lifterlms.com' );\n  } catch( LLMS_Unit_Test_Exception_Redirect $exception ) {\n    // Any additional assertions can be added here.\n    $this-\u003eassertTrue( ... );\n    throw $exception;\n  }\n}\n```\n\n\n## Factories\n\nTest cases which extend the `LLMS_Unit_Test_Case` class may access factories built off the WP Unit Tests Factories: `WP_UnitTest_Factory_For_Post` and `WP_UnitTest_Factory_For_User`\n\n##### Course Post Factory\n\nAccess the factory: `$this-\u003efactory-\u003ecourse`\n\nCreate a course and retrieve the course ID: `$course_id = $this-\u003efactory-\u003ecourse-\u003ecreate();`\n\nCreate a course and retrieve LLMS_Course object: `$course = $this-\u003efactory-\u003ecourse-\u003ecreate_and_get();`\n\nCreate a many courses: `$courses = $this-\u003efactory-\u003ecourse-\u003ecreate_many( 5 );`\n\nSpecify the number of sections, lessons, quizzes, and questions:\n\n```php\n$args = array(\n  'sections' =\u003e 2, // 2 sections in the course\n  'lessons' =\u003e 5, // 5 lessons per section\n  'quizzes' =\u003e 1, // 1 quiz per section (will always be the last lesson in the section)\n  'questions' =\u003e 5, // 5 questions per quiz\n);\n$course_id = $this-\u003efactory-\u003ecourse-\u003ecreate( $args );\n$course = $this-\u003efactory-\u003ecourse-\u003ecreate_and_get( $args );\n```\n\n##### Membership Post Factory\n\nAccess the factory: `$this-\u003efactory-\u003emembership`\n\nCreate a membership and retrieve the membership ID: `$membership_id = $this-\u003efactory-\u003emembership-\u003ecreate();`\n\nCreate a membership and retrieve LLMS_Membership object: `$membership = $this-\u003efactory-\u003emembership-\u003ecreate_and_get();`\n\nCreate a many memberships: `$memberships = $this-\u003efactory-\u003emembership-\u003ecreate_many( 5 );`\n\n\n##### Order Post Factory\n\nAccess the factory: `$this-\u003efactory-\u003eorder`\n\nCreate an order and retrieve the order ID: `$order_id = $this-\u003efactory-\u003eorder-\u003ecreate();`\n\nCreate an order and retrieve LLMS_Order object: `$order = $this-\u003efactory-\u003eorder-\u003ecreate_and_get();`\n\nCreate a many orders: `$orders = $this-\u003efactory-\u003eorder-\u003ecreate_many( 5 );`\n\nCreate an order and record a transaction for it LLMS_Order: `$order = $this-\u003efactory-\u003eorder-\u003ecreate_and_pay();`\n\n\n##### Student User Factory\n\nAccess the factory: `$this-\u003efactory-\u003estudent`\n\nCreate a student and retrieve the student ID: `$student_id = $this-\u003efactory-\u003estudent-\u003ecreate();`\n\nCreate a student and retrieve LLMS_Student object: `$student = $this-\u003efactory-\u003estudent-\u003ecreate_and_get();`\n\nCreate a many students: `$students = $this-\u003efactory-\u003estudent-\u003ecreate_many( 5 );`\n\nCreate a student(s) and enroll into a course/membership:\n\n```php\n$course_id = $this-\u003efactory-\u003ecourse-\u003ecreate();\n// single student\n$student_id = $this-\u003efactory-\u003estudent-\u003ecreate_and_enroll( $coursed_id );\n// multiple students\n$student_ids = $this-\u003efactory-\u003estudent-\u003ecreate_and_enroll_many( 5, $coursed_id );\n```\n\n\n##### Instructor User Factory\n\nAccess the factory: `$this-\u003efactory-\u003einstructor`\n\nCreate a instructor and retrieve the instructor ID: `$instructor_id = $this-\u003efactory-\u003einstructor-\u003ecreate();`\n\nCreate a instructor and retrieve LLMS_Instructor object: `$instructor = $this-\u003efactory-\u003einstructor-\u003ecreate_and_get();`\n\n\n## Cookies\n\nTest methods and functions that set cookies via `llms_setcookie` using the `LLMS_Tests_Cookies` class.\n\nAccess the class: `$this-\u003ecookies`.\n\n##### Set a cookie\n\n```php\n$this-\u003ecookies-\u003eset( $name, $value, ... )\n```\n\n##### Retrieve set cookie(s)\n\n```php\n$this-\u003ecookies-\u003eset( 'name', 'value', 0, ... );\n\n// Retrieve all cookies\n$cookies = $this-\u003ecookies-\u003eget_all();\nvar_dump( $cookies );\n// array(\n//   'name' =\u003e array(\n//      'value'   =\u003e 'value',\n//      'expires' =\u003e 0,\n//      ...\n//   ),\n// )\n//\n\n// Retrieve a single cookie.\n$cookie = $this-\u003ecookies-\u003eget( 'name' );\nvar_dump( $cookie );\n// array(\n//    'value'   =\u003e 'value',\n//    'expires' =\u003e 0,\n//    ...\n//   ),\n```\n\n##### Mock the expected response of llms_setcookie()\n\nMock a success response:\n\n```php\n$this-\u003ecookies-\u003eexpect_success();\n$this-\u003eassertTrue( llms_setcookie( 'name', 'val' ) );\n```\n\nIn the testing suite `llms_setcookie()` will always respond `true` so it's not necessary to call `expect_success()` unless you previously call `expect_error()` in the same test.\n\n\nMock an error response:\n\n```php\n$this-\u003ecookies-\u003eexpect_error();\n$this-\u003eassertFalse( llms_setcookie( 'name', 'val' ) );\n```\n\n\n##### Clear set cookie(s)\n\nClear all cookies:\n\n```php\n$this-\u003ecookies-\u003eunset_all()\nvar_dump( $this-\u003ecookies-\u003eget_all() );\n// array()\n```\n\nClear a single cookie by name:\n\n```php\nllms_setcookie( 'name', 'val' );\n$this-\u003ecookies-\u003eunset( 'name' );\nvar_dump( $this-\u003ecookies-\u003eget( 'name' ) );\n// null\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgocodebox%2Flifterlms-tests","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgocodebox%2Flifterlms-tests","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgocodebox%2Flifterlms-tests/lists"}