I'm trying to get my REST endpoint working. The following url gets 200 response in REST clients.
http://sign-up-api.local/v1/user/info
I'm getting this exception.
CodeceptionModuleYii2 can't open external URL
Provide console output if related. Use
-vvvmode for more details.
➜ src git:(master) ✗ composer exec codecept run -vvv api <<<
Reading ./composer.json
Loading config file /Users/seng/.composer/config.json
Loading config file /Users/seng/.composer/auth.json
Loading config file ./composer.json
Checked CA file /private/etc/ssl/cert.pem: valid
Executing command (/Users/seng/projects/plum-flower/sign-up-api/src): git branch --no-color --no-abbrev -v
Reading /Users/seng/.composer/composer.json
Loading config file /Users/seng/.composer/config.json
Loading config file /Users/seng/.composer/auth.json
Loading config file /Users/seng/.composer/composer.json
Loading config file /Users/seng/.composer/auth.json
Reading /Users/seng/.composer/auth.json
Reading /Users/seng/projects/plum-flower/sign-up-api/src/vendor/composer/installed.json
Reading /Users/seng/.composer/vendor/composer/installed.json
Loading plugin yii\composer\Plugin
Loading plugin Fxp\Composer\AssetPlugin\FxpAssetPlugin
Running 1.2.2 (2016-11-03 17:43:15) with PHP 7.1.0 on Darwin / 16.3.0
> __exec_command: codecept 'run' 'api'
Executing command (CWD): codecept 'run' 'api'
Codeception PHP Testing Framework v2.2.6
Powered by PHPUnit 5.7-dev by Sebastian Bergmann and contributors.
Api Tests (1) ----------------------------------------------------------------
E InfoCept: Get the public information for the main page via api (0.00s)
------------------------------------------------------------------------------
Time: 170 ms, Memory: 10.00MB
There was 1 error:
---------
1) InfoCept: Get the public information for the main page via api
Test tests/api/InfoCept.php
[ExternalUrlException] Codeception\Module\Yii2 can't open external URL: http://plum-flower-sign-up-api.local/v1/info/v1/info
Scenario Steps:
2. $I->sendGET("/v1/info") at tests/api/InfoCept.php:7
1. $I->haveHttpHeader("Content-Type","application/json") at tests/api/InfoCept.php:6
#1 Codeception\Module\REST->sendGET
#2 /Users/seng/projects/plum-flower/sign-up-api/src/tests/_support/_generated/ApiTesterActions.php:305
#3 /Users/seng/projects/plum-flower/sign-up-api/src/tests/api/InfoCept.php:7
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
Script codecept handling the __exec_command event returned with error code 1
Provide test source code if related
<?php
$I = new ApiTester($scenario);
$I->wantTo('Get the public information for the main page via API');
$I->haveHttpHeader('Content-Type', 'application/json');
$I->sendGET('/v1/info');
$I->seeResponseCodeIs(\Codeception\Util\HttpCode::OK); // 200
$I->seeResponseIsJson();
$I->seeResponseContainsJson([
'success' => true,
'data' => [
'info' => 'Some information about the <b>company</b>.'
]
]);
List of installed packages (composer show)
composer-packages.txt
Suite configuration:
# tests/api.suite.yml
class_name: ApiTester
modules:
enabled:
- REST:
url: http://plum-flower-sign-up-api.local/v1/info
depends: Yii2
- Yii2:
# codeception.yml
include:
- tests/codeception/common
- tests/codeception/console
- tests/codeception/backend
- tests/codeception/frontend
paths:
log: tests/codeception/_output
settings:
colors: true
db:
dsn:
username:
password:
You have wrong base API URL set up in the config thus Codeception is requesting http://plum-flower-sign-up-api.local/v1/info/v1/info. Adjust it:
enabled:
- REST:
url: http://plum-flower-sign-up-api.local
I'm sorry, it is a typo in the post. In the real code, it is, in fact, http://plum-flower-sign-up-api.local still throws the same exception
Why is the URL http://plum-flower-sign-up-api.local/v1/info/v1/info then?
I tried few other variations, when I posting the issue, I posted a wrong one. Give me a minute, let me post the exception with the aforementioned url.

Which type of test it is? Functional or acceptance?
I'm trying to do functional API tests only.
My main source of confusion is whether we need phpBrowser / Selenium to get REST api working. The documentation claims we don't need browser for functional testing, but REST functional testing does seem to require browser. The app is running via Vagrant, but I run these tests from host machine. Does vagrant setup have to do anything with this?
Functional API test sample code in doc includes phpBrowser
http://codeception.com/docs/10-WebServices
This is the only code snippet I have ever seen for Yii2 API functional test
https://github.com/githubjeka/yii2-rest/blob/master/tests/codeception/rest/functional.suite.yml
They seem to use port 8080. Why didn't they use port 80? Are they using Apache for running main application and use PHP's built-in browser for running tests?
@senguttuvang Don't use domain names in functional testing with Yii2 module unless you use domain based routes (if you had a matching domain route it would work).
Remove url option completely or change it to url: /v1/info
I don't know where you wanted me to make this change, but I have already tried every possible combination of URLs in both API.suite.XML file & tests/API/InfoCept.php
In all the cases, it throws 404 exceptions. It doesn't tell which URL it tried to encounter 404. I tried getting into the source code of Codeception, then went through Guzzle, but I got lost at one point.
How the codeception interprets the URL for functional tests? Will it hit the URL to get the result? When you hit the URL from the browser, the web server will populate these data for PHP scripts. How would it determine which URL to hit when running tests from the terminal if we skip url param?

Yii2 module doesn't fetch the url - it processes requests without making HTTP request.
The external URL exception was introduced to prevent framework modules from serving request when a link to another website was clicked.
Framework modules process requests to localhost and to other domains that are configured in domain based routes.
You are on a right path and you have to make the path part of your URLs match Yii2 routes.
Please share your route configuration if you can't figure it out.
Thank you very much for helping me out. I just ran my first functional test successfully after struggling with it for days!
I did not pay attention to config/test.php because I thought it is config/web.php who handles the app configuration. I copied my request, response & urlManager components from config/web.php to config/test.php and it succeeded.
Hello everyone,
I have been struggling with the same problem for a couple of days now. I have tried almost everything @senguttuvang & @samdark mentioned and much more. The only difference is that I am using a yii2-app-advanced template via Vagrant.
I have create a new app (api) with a new api codeception suite.
# api.suite.yml
actor: ApiTester
modules:
enabled:
- REST:
url: /api/v1
depends: Yii2
part: Json
- \api\tests\Helper\Api
config:
- Yii2
Here is a simple test
<?php
namespace api\tests;
use api\tests\ApiTester;
class ActivityCest
{
public function checkActivitiesUnauthorized(ApiTester $I)
{
$I->sendGET('/activities');
$I->seeResponseCodeIs(401); // Unauthorized
}
}
The API is working fine. Testing from my host machine http://localhost:4006/api/v1/activities I am getting the correct response, but when testing whatever I do the response is always 404.

Any ideas please?
@senguttuvang how did you configured your 'api/config/test.php' file?
Here are my configs:
<?php
// api/config/test-local.php
return yii\helpers\ArrayHelper::merge(
require(__DIR__ . '/../../common/config/test-local.php'),
require(__DIR__ . '/main.php'),
require(__DIR__ . '/main-local.php'),
require(__DIR__ . '/test.php'),
[
]
);
```php
// api/config/test.php
return [
];
```php
<?php
// api/config/main.php
$params = array_merge(
require(__DIR__ . '/../../common/config/params.php'), require(__DIR__ . '/../../common/config/params-local.php'), require(__DIR__ . '/params.php')
);
return [
'id' => 'app-api',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'controllerNamespace' => 'api\controllers',
'modules' => [
'v1' => [
'basePath' => '@app/modules/v1',
'class' => 'api\modules\v1\Module'
],
],
'components' => [
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => false,
'enableSession' => false,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => ['v1/activity'],
'extraPatterns' => [
'OPTIONS update' => 'options',
'POST update' => 'update',
]
],
],
],
'request' => [
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
],
],
'params' => $params,
];
All suggestions are welcome
@leoshtika and anyone else coming here looking for a valid configuration for the REST API testing, this is what I ended up with
class_name: Api2Tester
modules:
enabled:
- Filesystem
- Asserts
- Yii2
- REST:
url: /v2
depends: Yii2
part: Json
Note that my REST url is "/v2" and not "/api/v2". I'm not fully sure of why it's like that but I think it's caused by the 'controller' part of the following section in my configuration:
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false, // note: this is overwritten in main-local for localhost
'rules' => [
//Book
['class' => 'yii\rest\UrlRule',
'controller' => ['v2/book'],
'extraPatterns' => [
'GET index' => 'index',
'GET by-favorite-authors' => 'by-favorite-authors',
'GET currently-popular' => 'currently-popular',
'GET in-favorite-categories' => 'in-favorite-categories',
],
],
In my case the problem was that config/test.php didn't have module api defined so I was getting 404. Dunno how I couldn't figure out such a straight forward thing
Most helpful comment
Thank you very much for helping me out. I just ran my first functional test successfully after struggling with it for days!
I did not pay attention to config/test.php because I thought it is config/web.php who handles the app configuration. I copied my request, response & urlManager components from config/web.php to config/test.php and it succeeded.