Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kickoff testing #4

Merged
merged 3 commits into from
Dec 10, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ jobs:
run: composer install --no-scripts

- name: Lint PHP
run: php -l src/**/*.php
run: php -l src/**/*.php tests/**/*.php

- name: Lint Templates
run: bin/console lint:twig templates
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -27,3 +27,4 @@ phpstan.neon
###< phpunit/phpunit ###

chromadb
coverage
12 changes: 11 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -106,6 +106,16 @@
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd",
"importmap:install": "symfony-cmd"
}
},
"pipeline": [
"composer validate --strict",
"php -l src/**/*.php tests/**/*.php",
"bin/console lint:twig templates",
"bin/console lint:yaml config",
"bin/console lint:container",
"PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --dry-run",
"phpstan analyse",
"XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-html=coverage"
]
}
}
7 changes: 4 additions & 3 deletions src/ProfilerSubscriber.php
Original file line number Diff line number Diff line change
@@ -4,17 +4,18 @@

namespace App;

use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelInterface;

/**
* Can be deleted with Symfony 7.3, see https://github.com/symfony/symfony/pull/59123.
*/
final class ProfilerSubscriber implements EventSubscriberInterface
{
public function __construct(
private KernelInterface $kernel,
#[Autowire('kernel.debug')]
private readonly bool $debug,
) {
}

@@ -27,7 +28,7 @@ public static function getSubscribedEvents(): array

public function onKernelResponse(ResponseEvent $event): void
{
if (!$this->kernel->isDebug()) {
if (!$this->debug && !$event->isMainRequest()) {
return;
}

33 changes: 21 additions & 12 deletions templates/index.html.twig
Original file line number Diff line number Diff line change
@@ -23,10 +23,13 @@
<p class="card-text">Retrieval Augmented Generation based on Symfony's blog dumped to a vector store.</p>
<a href="{{ path('rag') }}" class="btn btn-outline-dark d-block">Try RAG Chat Bot</a>
</div>
<div class="card-footer">
{{ ux_icon('solar:code-linear', { height: '20px', width: '20px' }) }}
<a href="{{ path('_profiler_open_file', { file: 'src/Chat/Rag.php', line: 14 }) }}">See Implementation</a>
</div>
{# Profiler route only available in dev #}
{% if 'dev' == app.environment %}
<div class="card-footer">
{{ ux_icon('solar:code-linear', { height: '20px', width: '20px' }) }}
<a href="{{ path('_profiler_open_file', { file: 'src/Chat/Rag.php', line: 14 }) }}">See Implementation</a>
</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
@@ -39,10 +42,13 @@
<p class="card-text">Question answering initialized with transcript of YouTube video.</p>
<a href="{{ path('youtube') }}" class="btn btn-outline-dark d-block">Try YouTube Transcript Bot</a>
</div>
<div class="card-footer">
{{ ux_icon('solar:code-linear', { height: '20px', width: '20px' }) }}
<a href="{{ path('_profiler_open_file', { file: 'src/Chat/YouTube.php', line: 15 }) }}">See Implementation</a>
</div>
{# Profiler route only available in dev #}
{% if 'dev' == app.environment %}
<div class="card-footer">
{{ ux_icon('solar:code-linear', { height: '20px', width: '20px' }) }}
<a href="{{ path('_profiler_open_file', { file: 'src/Chat/YouTube.php', line: 15 }) }}">See Implementation</a>
</div>
{% endif %}
</div>
</div>
<div class="col-md-4">
@@ -55,10 +61,13 @@
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="{{ path('wikipedia') }}" class="btn btn-outline-dark d-block">Try Wikipedia Research Bot</a>
</div>
<div class="card-footer">
{{ ux_icon('solar:code-linear', { height: '20px', width: '20px' }) }}
<a href="{{ path('_profiler_open_file', { file: 'src/Chat/Wikipedia.php', line: 14 }) }}">See Implementation</a>
</div>
{# Profiler route only available in dev #}
{% if 'dev' == app.environment %}
<div class="card-footer">
{{ ux_icon('solar:code-linear', { height: '20px', width: '20px' }) }}
<a href="{{ path('_profiler_open_file', { file: 'src/Chat/Wikipedia.php', line: 14 }) }}">See Implementation</a>
</div>
{% endif %}
</div>
</div>
</div>
61 changes: 61 additions & 0 deletions tests/ProfilerSubscriberTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

namespace App\Tests;

use App\Kernel;
use App\ProfilerSubscriber;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;

#[CoversClass(ProfilerSubscriber::class)]
final class ProfilerSubscriberTest extends TestCase
{
#[DataProvider('provideInvalidRequests')]
public function testAjaxReplaceHeaderNotSet(int $requestType, bool $debug, bool $isXmlHttpRequest): void
{
$request = new Request();
if ($isXmlHttpRequest) {
$request->headers->set('X-Requested-With', 'XMLHttpRequest');
}

$response = new Response();
$event = new ResponseEvent($this->createMock(Kernel::class), new Request(), $requestType, $response);

$listener = new ProfilerSubscriber($debug);
$listener->onKernelResponse($event);

$this->assertFalse($response->headers->has('Symfony-Debug-Toolbar-Replace'));
}

/**
* @return iterable<array{int, bool, bool}>
*/
public static function provideInvalidRequests(): iterable
{
yield 'sub request, not debug, not XHR' => [HttpKernelInterface::SUB_REQUEST, false, false];
yield 'sub request, not debug, XHR' => [HttpKernelInterface::SUB_REQUEST, false, true];
yield 'sub request, debug, XHR' => [HttpKernelInterface::SUB_REQUEST, true, true];
yield 'main request, not debug, not XHR' => [HttpKernelInterface::MAIN_REQUEST, false, false];
yield 'main request, debug, not XHR' => [HttpKernelInterface::MAIN_REQUEST, true, false];
}

public function testAjaxReplaceHeaderOnEnabledAndXHR(): void
{
$request = new Request();
$request->headers->set('X-Requested-With', 'XMLHttpRequest');
$response = new Response();
$event = new ResponseEvent($this->createMock(Kernel::class), $request, HttpKernelInterface::MAIN_REQUEST, $response);

$listener = new ProfilerSubscriber(true);
$listener->onKernelResponse($event);

$this->assertEquals('1', $response->headers->get('Symfony-Debug-Toolbar-Replace'));
}
}
55 changes: 55 additions & 0 deletions tests/SmokeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace App\Tests;

use PHPUnit\Framework\Attributes\CoversNothing;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\UX\LiveComponent\Test\InteractsWithLiveComponents;

#[CoversNothing]
final class SmokeTest extends WebTestCase
{
use InteractsWithLiveComponents;

public function testIndex(): void
{
$client = static::createClient();
$client->request('GET', '/');

self::assertResponseIsSuccessful();
self::assertSelectorTextContains('h1', 'Welcome');
self::assertSelectorCount(3, '.card');
}

public function testRag(): void
{
$client = static::createClient();
$client->request('GET', '/rag');

self::assertResponseIsSuccessful();
self::assertSelectorTextContains('h4', 'Retrieval Augmented Generation with the Symfony blog');
self::assertSelectorCount(1, '#chat-submit');
}

public function testYouTube(): void
{
$client = static::createClient();
$client->request('GET', '/youtube');

self::assertResponseIsSuccessful();
self::assertSelectorTextContains('h4', 'Chat about a YouTube Video');
self::assertSelectorCount(1, '#chat-submit');
}

public function testWikipedia(): void
{
$client = static::createClient();
$client->request('GET', '/wikipedia');

self::assertResponseIsSuccessful();
self::assertSelectorTextContains('h4', 'Wikipedia Research');
self::assertSelectorCount(1, '#chat-submit');
}
}
27 changes: 27 additions & 0 deletions tests/YouTube/TranscriptFetcherTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace App\Tests\YouTube;

use App\YouTube\TranscriptFetcher;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;

#[CoversClass(TranscriptFetcher::class), ]
final class TranscriptFetcherTest extends TestCase
{
public function testFetchTranscript(): void
{
$videoResponse = MockResponse::fromFile(__DIR__.'/fixtures/video.html');
$transcriptResponse = MockResponse::fromFile(__DIR__.'/fixtures/transcript.xml');
$mockClient = new MockHttpClient([$videoResponse, $transcriptResponse]);

$fetcher = new TranscriptFetcher($mockClient);
$transcript = $fetcher->fetchTranscript('6uXW-ulpj0s');

self::assertStringContainsString('symphony is a PHP framework', $transcript);
}
}
66 changes: 66 additions & 0 deletions tests/YouTube/fixtures/transcript.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8" ?>
<transcript>
<text start="2.12" dur="5.679">symphony is a PHP framework and this is</text>
<text start="5.22" dur="5.1">an advantage why because almost 80</text>
<text start="7.799" dur="5.88">percent of all websites in the internet</text>
<text start="10.32" dur="5.22">use PHP as a server-side language eighty</text>
<text start="13.679" dur="4.141">percent this does mean that wherever you</text>
<text start="15.54" dur="4.68">are right now there is someone near you</text>
<text start="17.82" dur="4.86">probably searching to hire a PHP</text>
<text start="20.22" dur="4.799">developer Symphony will not only teach</text>
<text start="22.68" dur="4.859">you more PHP but also will teach you</text>
<text start="25.019" dur="4.141">different software architecture patterns</text>
<text start="27.539" dur="4.201">that you can use in different languages</text>
<text start="29.16" dur="4.44">software architecture patterns are so</text>
<text start="31.74" dur="3.12">much important in your skill sets</text>
<text start="33.6" dur="4.02">because they allow you to understand</text>
<text start="34.86" dur="4.92">complex software when you only know the</text>
<text start="37.62" dur="3.72">architecture that was used in that</text>
<text start="39.78" dur="3.959">software please let me tell you a story</text>
<text start="41.34" dur="4.02">that happened to me I had a PHP laravel</text>
<text start="43.739" dur="4.861">interview in a company and the interview</text>
<text start="45.36" dur="5.219">was successful so they invite me for a</text>
<text start="48.6" dur="4.04">test work day and that test work day</text>
<text start="50.579" dur="4.62">they asked me to build an application</text>
<text start="52.64" dur="4.18">using.net and Seashore they told me we</text>
<text start="55.199" dur="3.84">know you didn&amp;#39;t had any previous</text>
<text start="56.82" dur="4.32">experience using C sharp but we want to</text>
<text start="59.039" dur="3.721">see how you can get along with different</text>
<text start="61.14" dur="4.32">programming language I was able to</text>
<text start="62.76" dur="5.46">Google and found out that the dotnet</text>
<text start="65.46" dur="5.04">framework is an MVC architect framework</text>
<text start="68.22" dur="4.32">the same framework is used in Symphony</text>
<text start="70.5" dur="4.32">and Bam I built the application in</text>
<text start="72.54" dur="4.8">c-sharp and I got a wonderful job offer</text>
<text start="74.82" dur="4.979">so yes learning Symphony will teach you</text>
<text start="77.34" dur="5.16">software architecture patterns that are</text>
<text start="79.799" dur="5.281">essential in your skill set symphony is</text>
<text start="82.5" dur="4.979">a full stack framework that mean you can</text>
<text start="85.08" dur="4.5">create deploy ready application you will</text>
<text start="87.479" dur="5.341">be using front-end Technologies like</text>
<text start="89.58" dur="6.24">HTML CSS and JavaScript and back-end or</text>
<text start="92.82" dur="5.52">server Technologies like PHP databases</text>
<text start="95.82" dur="5.1">that will process the user request all</text>
<text start="98.34" dur="5.279">in one place Symphony can integrate</text>
<text start="100.92" dur="5.699">easily with modern JavaScript Frameworks</text>
<text start="103.619" dur="5.761">like vue.js or react.js or even you can</text>
<text start="106.619" dur="5.161">set up different databases like MySQL</text>
<text start="109.38" dur="4.98">postgres or whatever you want Symphony</text>
<text start="111.78" dur="4.799">has a CLI tool that can help build and</text>
<text start="114.36" dur="4.92">speak and debug your application and is</text>
<text start="116.579" dur="5.04">one of the most advanced code generation</text>
<text start="119.28" dur="4.14">tool in the planner is relate in the</text>
<text start="121.619" dur="4.921">comment if you know anything that is</text>
<text start="123.42" dur="5.039">good finally documentation Symphony has</text>
<text start="126.54" dur="4.74">good documentation that will make it</text>
<text start="128.459" dur="5.761">easy for newcomers to learn and have fun</text>
<text start="131.28" dur="4.86">with the technology so that was my 6y2</text>
<text start="134.22" dur="3.54">simple normally I don&amp;#39;t do this but</text>
<text start="136.14" dur="3.179">right now go and check the description</text>
<text start="137.76" dur="3.3">see the comment and write me what you</text>
<text start="139.319" dur="3.301">think like the video and subscribe to my</text>
<text start="141.06" dur="3.06">channel then go to the channel check the</text>
<text start="142.62" dur="2.759">videos and like each one of them and</text>
<text start="144.12" dur="4.759">comment again and come back to this</text>
<text start="145.379" dur="3.5">video and watch it again thank you</text>
</transcript>
88 changes: 88 additions & 0 deletions tests/YouTube/fixtures/video.html

Large diffs are not rendered by default.