Skip to content

Commit 70fdfac

Browse files
committed
Add "Multiple Ways to Declare Tests"; fix CodeTabs in light theme
1 parent 9fa3a79 commit 70fdfac

6 files changed

Lines changed: 248 additions & 15 deletions

File tree

.vitepress/theme/CodeTabs.vue

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ const iconMap: Record<string, { light: string; dark: string }> = {
3232
light: '/icon/light-khinkali-bordered.svg',
3333
dark: '/icon/dark-khinkali-bordered.svg',
3434
},
35+
'class': {
36+
light: '/icon/light-class.svg',
37+
dark: '/icon/dark-class.svg',
38+
},
3539
}
3640
3741
const getIcon = (tab: Tab) => {
@@ -81,8 +85,8 @@ const getIcon = (tab: Tab) => {
8185
/* Tabs */
8286
.ide-tabs {
8387
display: flex;
84-
background: #252526;
85-
border-bottom: 1px solid rgba(255,255,255,0.1);
88+
background: var(--vp-c-bg-soft);
89+
border-bottom: 1px solid var(--vp-c-divider);
8690
overflow-x: auto;
8791
border-radius: 12px 12px 0 0;
8892
scrollbar-width: none; /* Firefox */
@@ -93,10 +97,6 @@ const getIcon = (tab: Tab) => {
9397
display: none; /* Chrome/Safari */
9498
}
9599
96-
.dark .ide-tabs {
97-
background: #1e1e1e;
98-
}
99-
100100
.ide-tab:first-child {
101101
border-radius: 12px 0 0 0;
102102
}
@@ -105,11 +105,11 @@ const getIcon = (tab: Tab) => {
105105
display: flex;
106106
align-items: center;
107107
gap: 8px;
108-
padding: 10px 16px;
108+
padding: 4px 10px;
109109
background: transparent;
110110
border: none;
111-
border-right: 1px solid rgba(255,255,255,0.05);
112-
color: #888;
111+
border-right: 1px solid var(--vp-c-divider);
112+
color: var(--vp-c-text-3);
113113
font-size: 13px;
114114
font-family: var(--vp-font-family-base);
115115
cursor: pointer;
@@ -118,13 +118,13 @@ const getIcon = (tab: Tab) => {
118118
}
119119
120120
.ide-tab:hover {
121-
background: rgba(255,255,255,0.05);
122-
color: #ccc;
121+
background: var(--vp-c-bg-alt);
122+
color: var(--vp-c-text-2);
123123
}
124124
125125
.ide-tab.active {
126126
background: var(--vp-code-block-bg);
127-
color: #fff;
127+
color: var(--vp-c-text-1);
128128
border-bottom: 2px solid var(--vp-c-brand-1);
129129
margin-bottom: -1px;
130130
}

.vitepress/theme/style.css

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@
254254
}
255255

256256
.home-feature-text {
257-
flex: 1;
257+
flex: 2;
258258
text-align: left;
259259
}
260260

@@ -293,9 +293,8 @@
293293
}
294294

295295
.home-feature-code {
296-
flex: 1;
296+
flex: 3;
297297
min-width: 0;
298-
width: 100%;
299298
}
300299

301300
.home-feature-code .code-tabs-ide {
@@ -308,4 +307,10 @@
308307
flex-direction: column;
309308
gap: 32px;
310309
}
310+
311+
.home-feature-text,
312+
.home-feature-code {
313+
flex: none;
314+
width: 100%;
315+
}
311316
}

index.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ const assertTabs = [
4646
{ name: 'Exception.php', slot: 'expectException', icon: 'testo' },
4747
{ name: 'Attributes.php', slot: 'expectAttr', icon: 'testo-class' },
4848
]
49+
50+
const declareTabs = [
51+
{ name: 'Class', slot: 'declare-class', icon: 'testo-class' },
52+
{ name: 'Function', slot: 'declare-function', icon: 'testo-function' },
53+
{ name: 'Convention', slot: 'declare-convention', icon: 'testo-class' },
54+
{ name: 'Inline', slot: 'declare-inline', icon: 'class' },
55+
]
4956
</script>
5057

5158
<div class="home-feature">
@@ -139,6 +146,108 @@ public function testInvalidInput(): void
139146
</div>
140147
</div>
141148

149+
<div class="home-feature">
150+
151+
## Multiple Ways to Declare Tests
152+
153+
<div class="home-feature-row home-feature-row-reverse">
154+
<div class="home-feature-text">
155+
156+
Write tests the way that fits your style.
157+
158+
- Tests can be classes, functions, or even attributes right in production code (Inline Tests).
159+
- Classes don't need to inherit from a base test class. Code stays clean.
160+
- Test discovery by naming conventions or explicit attributes.
161+
162+
</div>
163+
<div class="home-feature-code">
164+
<CodeTabs :tabs="declareTabs">
165+
166+
<template #declare-class>
167+
168+
```php
169+
// Explicit test declaration with #[Test] attribute
170+
171+
final class OrderTest
172+
{
173+
#[Test]
174+
public function createsOrderWithItems(): void
175+
{
176+
$order = new Order();
177+
$order->addItem(new Product('Bread'));
178+
179+
Assert::int($order->itemCount())->equals(1);
180+
}
181+
}
182+
```
183+
184+
</template>
185+
186+
<template #declare-function>
187+
188+
```php
189+
// Explicit test with #[Test] attribute
190+
// or "test" prefix in function name
191+
192+
#[Test]
193+
function validates_email_format(): void
194+
{
195+
$validator = new EmailValidator();
196+
197+
Assert::true($validator->isValid('user@example.com'));
198+
Assert::false($validator->isValid('invalid'));
199+
}
200+
201+
function testEmailValidator(): void { ... }
202+
```
203+
204+
</template>
205+
206+
<template #declare-convention>
207+
208+
```php
209+
// "Test" suffix on class and "test" prefix on methods
210+
211+
final class UserServiceTest
212+
{
213+
public function testCreatesUser(): void
214+
{
215+
$user = $this->service->create('john@example.com');
216+
217+
Assert::string($user->email)->contains('@');
218+
}
219+
220+
public function testDeletesUser(): void { /* ... */ }
221+
}
222+
```
223+
224+
</template>
225+
226+
<template #declare-inline>
227+
228+
```php
229+
// Test the method right in your code
230+
// Convenient for simple cases
231+
232+
final class Calculator
233+
{
234+
#[TestInline([1, 1], 2)]
235+
#[TestInline([40, 2], 42)]
236+
#[TestInline([-5, 5], 0)]
237+
public function sum(int $a, int $b): int
238+
{
239+
return $a + $b;
240+
}
241+
}
242+
```
243+
244+
</template>
245+
246+
</CodeTabs>
247+
</div>
248+
</div>
249+
</div>
250+
142251
<div class="sponsors-section">
143252
<h2 class="sponsors-title">Sponsored by</h2>
144253
<div class="sponsors-grid">

public/icon/dark-class.svg

Lines changed: 5 additions & 0 deletions
Loading

public/icon/light-class.svg

Lines changed: 5 additions & 0 deletions
Loading

ru/index.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ const assertTabs = [
4646
{ name: 'Exception.php', slot: 'expectException', icon: 'testo' },
4747
{ name: 'Attributes.php', slot: 'expectAttr', icon: 'testo-class' },
4848
]
49+
50+
const declareTabs = [
51+
{ name: 'Класс', slot: 'declare-class', icon: 'testo-class' },
52+
{ name: 'Функция', slot: 'declare-function', icon: 'testo-function' },
53+
{ name: 'Конвенция', slot: 'declare-convention', icon: 'testo-class' },
54+
{ name: 'Inline', slot: 'declare-inline', icon: 'class' },
55+
]
4956
</script>
5057

5158
<div class="home-feature">
@@ -139,6 +146,108 @@ public function testInvalidInput(): void
139146
</div>
140147
</div>
141148

149+
<div class="home-feature">
150+
151+
## Разные способы объявления тестов
152+
153+
<div class="home-feature-row home-feature-row-reverse">
154+
<div class="home-feature-text">
155+
156+
Пишите тесты так, как удобно вам.
157+
158+
- Тестами могут быть классы, функции или даже атрибуты прямо в продуктовом коде (Inline Tests).
159+
- Классам не нужно наследование от базового тестового класса. Код остаётся чистым.
160+
- Обнаружение тестов по соглашениям об именовании или по явным атрибутам.
161+
162+
</div>
163+
<div class="home-feature-code">
164+
<CodeTabs :tabs="declareTabs">
165+
166+
<template #declare-class>
167+
168+
```php
169+
// Явное объявление теста в методе с атрибутом #[Test]
170+
171+
final class OrderTest
172+
{
173+
#[Test]
174+
public function createsOrderWithItems(): void
175+
{
176+
$order = new Order();
177+
$order->addItem(new Product('Bread'));
178+
179+
Assert::int($order->itemCount())->equals(1);
180+
}
181+
}
182+
```
183+
184+
</template>
185+
186+
<template #declare-function>
187+
188+
```php
189+
// Явное обозначение теста атрибутом #[Test]
190+
// или префиксом "test" в имени функции
191+
192+
#[Test]
193+
function validates_email_format(): void
194+
{
195+
$validator = new EmailValidator();
196+
197+
Assert::true($validator->isValid('user@example.com'));
198+
Assert::false($validator->isValid('invalid'));
199+
}
200+
201+
function testEmailValidator(): void { ... }
202+
```
203+
204+
</template>
205+
206+
<template #declare-convention>
207+
208+
```php
209+
// Суффикс "Test" на классе и префикс "test" на методах
210+
211+
final class UserServiceTest
212+
{
213+
public function testCreatesUser(): void
214+
{
215+
$user = $this->service->create('john@example.com');
216+
217+
Assert::string($user->email)->contains('@');
218+
}
219+
220+
public function testDeletesUser(): void { /* ... */ }
221+
}
222+
```
223+
224+
</template>
225+
226+
<template #declare-inline>
227+
228+
```php
229+
// Тестируем метод прямо в коде
230+
// Для простых случаев удобно
231+
232+
final class Calculator
233+
{
234+
#[TestInline([1, 1], 2)]
235+
#[TestInline([40, 2], 42)]
236+
#[TestInline([-5, 5], 0)]
237+
public function sum(int $a, int $b): int
238+
{
239+
return $a + $b;
240+
}
241+
}
242+
```
243+
244+
</template>
245+
246+
</CodeTabs>
247+
</div>
248+
</div>
249+
</div>
250+
142251
<div class="sponsors-section">
143252
<h2 class="sponsors-title">Спонсоры</h2>
144253
<div class="sponsors-grid">

0 commit comments

Comments
 (0)