Skip to content

Commit a5c9ff8

Browse files
committed
Fix API calls and write unit tests
1 parent aebcf67 commit a5c9ff8

File tree

13 files changed

+689
-519
lines changed

13 files changed

+689
-519
lines changed

.idea/leantime-oss.iml

-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/Core/Http/HttpKernel.php

+8-5
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,8 @@ class HttpKernel extends Kernel
4141
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
4242
\Leantime\Core\Middleware\TrimStrings::class,
4343
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
44-
\Leantime\Core\Middleware\Auth::class,
45-
\Leantime\Core\Middleware\ApiAuth::class,
4644
\Leantime\Core\Middleware\SetCacheHeaders::class,
4745
\Leantime\Core\Middleware\Localization::class,
48-
\Leantime\Core\Middleware\CurrentProject::class,
4946
\Leantime\Core\Middleware\LoadPlugins::class,
5047
];
5148

@@ -57,15 +54,13 @@ class HttpKernel extends Kernel
5754
protected $middlewareGroups = [
5855
'web' => [
5956
\Leantime\Core\Middleware\Auth::class,
60-
\Leantime\Core\Middleware\Localization::class,
6157
\Leantime\Core\Middleware\CurrentProject::class,
6258
],
6359
'api' => [
6460
\Leantime\Core\Middleware\ApiAuth::class,
6561
],
6662
'hx' => [
6763
\Leantime\Core\Middleware\Auth::class,
68-
\Leantime\Core\Middleware\Localization::class,
6964
\Leantime\Core\Middleware\CurrentProject::class,
7065
],
7166
];
@@ -103,6 +98,14 @@ protected function sendRequestThroughRouter($request)
10398
//Can savely assume events are available here.
10499
self::dispatch_event('request_started', ['request' => $request]);
105100

101+
if ($request instanceof ApiRequest) {
102+
103+
array_splice($this->middleware, 5, 0, $this->middlewareGroups['api']);
104+
105+
} else {
106+
array_splice($this->middleware, 5, 0, $this->middlewareGroups['web']);
107+
}
108+
106109
//This filter only works for system plugins
107110
//Regular plugins are not available until after install verification
108111
$this->middleware = self::dispatch_filter('middleware', $this->middleware, ['request' => $request]);

app/Domain/Api/Controllers/Jsonrpc.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function init(): void
4141
*/
4242
public function post(array $params): Response
4343
{
44-
if (empty($params)) {
44+
if (empty($params) || isset($params['act'])) {
4545
$params = $this->json_data;
4646
}
4747

app/Language/en-US.ini

+2
Original file line numberDiff line numberDiff line change
@@ -2584,3 +2584,5 @@ widget.descriptions.implementation_intentions = "Daily Intentions are a strategy
25842584
titles.account_details = "😀 Setting Account Details"
25852585
titles.determine_visual_experience = "👀 Determining A Visual Experience"
25862586
text.choose_a_theme_and_font_easy_to_read = "You can choose a theme and font that is easy on your brain."
2587+
2588+
label.asdf = ""

makefile

+7-3
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ package: clean build
6262
# Removing unneeded items for release
6363
rm -rf $(TARGET_DIR)/public/dist/images/Screenshots
6464

65-
# Removing js directories
65+
# Removing javascript directories
6666
find $(TARGET_DIR)/app/Domain/ -depth -maxdepth 2 -name "js" -exec rm -rf {} \;
6767

68-
# Removing un-compiled js files
68+
# Removing un-compiled javascript files
6969
find $(TARGET_DIR)/public/dist/js/ -depth -mindepth 1 ! -name "*compiled*" -exec rm -rf {} \;
7070

7171
#create zip files
@@ -114,6 +114,11 @@ unit-test: build-dev
114114
docker compose --file .dev/docker-compose.yaml --file .dev/docker-compose.tests.yaml exec leantime-dev php vendor/bin/codecept build
115115
docker compose --file .dev/docker-compose.yaml --file .dev/docker-compose.tests.yaml exec leantime-dev php vendor/bin/codecept run Unit -vv
116116

117+
api-test: build-dev
118+
docker compose --file .dev/docker-compose.yaml --file .dev/docker-compose.tests.yaml up --detach --build --remove-orphans
119+
docker compose --file .dev/docker-compose.yaml --file .dev/docker-compose.tests.yaml exec leantime-dev php vendor/bin/codecept build
120+
docker compose --file .dev/docker-compose.yaml --file .dev/docker-compose.tests.yaml exec leantime-dev php vendor/bin/codecept run Api -vv
121+
117122
acceptance-test-ci: build-dev
118123
docker compose --file .dev/docker-compose.yaml --file .dev/docker-compose.tests.yaml up --detach --build --remove-orphans
119124
docker compose --file .dev/docker-compose.yaml --file .dev/docker-compose.tests.yaml exec leantime-dev php vendor/bin/codecept build
@@ -148,4 +153,3 @@ clear-cache:
148153
rm -rf ./storage/framework/views/*.php
149154

150155
.PHONY: install-deps build-js build package clean run-dev
151-

tests/Acceptance.suite.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ bootstrap: bootstrap.php
88
modules:
99
enabled:
1010
- \Tests\Support\Helper\Acceptance
11+
- REST:
12+
url: 'https://leantime-dev'
13+
depends: PhpBrowser
1114
- WebDriver:
1215
url: 'https://leantime-dev'
1316
host: selenium
@@ -19,7 +22,6 @@ modules:
1922
acceptInsecureCerts: true
2023
goog:chromeOptions:
2124
args: [ "--headless" ]
22-
2325
- Db:
2426
dsn: "mysql:host=db;port=3306;dbname=leantime_test"
2527
user: leantime

tests/Acceptance/ApiCest.php

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?php
2+
3+
namespace Acceptance;
4+
5+
use Codeception\Attribute\Group;
6+
use Tests\Support\AcceptanceTester;
7+
use Tests\Support\Page\Acceptance\Install;
8+
use Tests\Support\Page\Acceptance\Login;
9+
10+
class ApiCest
11+
{
12+
private string $apiKey;
13+
14+
private Login $loginPage;
15+
16+
private Install $installPage;
17+
18+
public function _before(AcceptanceTester $I, Login $loginPage, Install $installPage)
19+
{
20+
$this->loginPage = $loginPage;
21+
$this->installPage = $installPage;
22+
23+
// Ensure database is installed before running API tests
24+
$this->installPage->install(
25+
26+
'test',
27+
'John',
28+
'Smith',
29+
'Smith & Co'
30+
);
31+
}
32+
33+
#[Group('api')]
34+
public function createAPIKey(AcceptanceTester $I)
35+
{
36+
37+
$this->loginPage->login('[email protected]', 'test');
38+
39+
// Generate API key if not exists
40+
$I->amOnPage('setting/editCompanySettings#/api/newApiKey');
41+
$I->waitForElementVisible('#firstname', 120);
42+
43+
$I->fillField(['id' => 'firstname'], 'APIUser');
44+
$I->selectOption(['id' => 'role'], 'Administrator');
45+
$I->checkOption('Leantime Onboarding');
46+
$I->clickWithRetry('#save');
47+
48+
$I->waitForElement('#apiKey');
49+
50+
$this->apiKey = $I->grabValueFrom('#apiKey');
51+
52+
codecept_debug($this->apiKey);
53+
}
54+
55+
#[Group('api')]
56+
public function testJsonRpcEndpoint(AcceptanceTester $I)
57+
{
58+
59+
$I->haveHttpHeader('Content-Type', 'application/json');
60+
$I->haveHttpHeader('x-api-key', $this->apiKey);
61+
62+
$I->sendPost('/api/jsonrpc', [
63+
'jsonrpc' => '2.0',
64+
'method' => 'leantime.rpc.Comments.pollComments',
65+
'params' => ['projectId' => 1],
66+
'id' => 1,
67+
]);
68+
69+
$I->seeResponseCodeIs(200);
70+
$I->seeResponseIsJson();
71+
$I->seeResponseMatchesJsonType([
72+
'jsonrpc' => 'string',
73+
'result' => 'array',
74+
'id' => 'string',
75+
]);
76+
}
77+
78+
#[Group('api')]
79+
public function testInvalidJsonRpcRequest(AcceptanceTester $I)
80+
{
81+
$I->haveHttpHeader('Content-Type', 'application/json');
82+
$I->haveHttpHeader('x-api-key', $this->apiKey);
83+
84+
$I->sendPost('/api/jsonrpc', [
85+
'jsonrpc' => '2.0',
86+
'method' => 'invalid.method',
87+
'params' => ['projectId' => 1],
88+
'id' => 1,
89+
]);
90+
91+
$I->seeResponseCodeIs(200);
92+
$I->seeResponseIsJson();
93+
$I->seeResponseMatchesJsonType([
94+
'jsonrpc' => 'string',
95+
'error' => [
96+
'code' => 'integer',
97+
'message' => 'string',
98+
'data' => 'string'
99+
],
100+
'id' => 'integer',
101+
]);
102+
103+
104+
}
105+
106+
#[Group('api')]
107+
public function testValidReturnId(AcceptanceTester $I)
108+
{
109+
$I->haveHttpHeader('Content-Type', 'application/json');
110+
$I->haveHttpHeader('x-api-key', $this->apiKey);
111+
112+
$I->sendPost('/api/jsonrpc', [
113+
'jsonrpc' => '2.0',
114+
'method' => 'leantime.rpc.Comments.pollComments',
115+
'params' => ['projectId' => 1],
116+
'id' => 123,
117+
]);
118+
119+
$I->seeResponseCodeIs(200);
120+
$I->seeResponseIsJson([
121+
'jsonrpc' => '2.0',
122+
'method' => 'leantime.rpc.Comments.pollComments',
123+
'params' => ['projectId' => 1],
124+
'id' => 'integer',
125+
]);
126+
127+
}
128+
129+
public function testMissingApiKey(AcceptanceTester $I)
130+
{
131+
$I->haveHttpHeader('Content-Type', 'application/json');
132+
133+
$I->sendPost('/api/jsonrpc', [
134+
'jsonrpc' => '2.0',
135+
'method' => 'leantime.rpc.Comments.pollComments',
136+
'params' => ['projectId' => 1],
137+
'id' => 1,
138+
]);
139+
140+
$I->seeResponseCodeIs(401);
141+
}
142+
}

tests/Acceptance/InstallCest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class InstallCest
1111
{
1212
public function _before(AcceptanceTester $I) {}
1313

14-
#[Group('install')]
14+
#[Group('install, api')]
1515
public function installPageWorks(AcceptanceTester $I): void
1616
{
1717
$I->amOnPage('/install');
@@ -20,7 +20,7 @@ public function installPageWorks(AcceptanceTester $I): void
2020
$I->see('Install');
2121
}
2222

23-
#[Group('install')]
23+
#[Group('install, api')]
2424
#[Depends('installPageWorks')]
2525
public function createDBSuccessfully(AcceptanceTester $I, Install $installPage): void
2626
{

tests/Support/ApiTester.php

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
namespace Tests\Support;
3+
4+
/**
5+
* Inherited Methods
6+
* @method void wantToTest($text)
7+
* @method void wantTo($text)
8+
* @method void execute($callable)
9+
* @method void expectTo($prediction)
10+
* @method void expect($prediction)
11+
* @method void amGoingTo($argumentation)
12+
* @method void am($role)
13+
* @method void lookForwardTo($achieveValue)
14+
* @method void comment($description)
15+
* @method void pause()
16+
*/
17+
class ApiTester extends \Codeception\Actor
18+
{
19+
use _generated\ApiTesterActions;
20+
}

tests/Support/Helper/Api.php

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
namespace Tests\Support\Helper;
3+
4+
use Codeception\Module;
5+
use Leantime\Core\Application;
6+
7+
class Api extends Module
8+
{
9+
protected Application $app;
10+
11+
public function _initialize()
12+
{
13+
$this->app = require dirname(__DIR__, 2).'/bootstrap.php';
14+
15+
}
16+
17+
public function getApplication(): Application
18+
{
19+
return $this->app;
20+
}
21+
22+
public function haveHttpHeader($header, $value)
23+
{
24+
$this->getModule('REST')->haveHttpHeader($header, $value);
25+
}
26+
}

0 commit comments

Comments
 (0)