Verified Commit 008cf1b7 authored by Korko's avatar Korko
Browse files

Convert tests to Pest

parent beca0ad0
Pipeline #381828 failed with stages
in 1 minute and 15 seconds
This diff is collapsed.
<?php
// Should return an array of sets which is an array of arguments and should also be an array of participants which is an array of fields
// So return [[[['name' => '']]]]
// Invalid list when there's no solution
dataset('invalid participants list', function () {
return [
[[
['name' => uniqid(), 'email' => 'test@test.com', 'exclusions' => [2]],
['name' => uniqid(), 'email' => 'test2@test.com', 'exclusions' => [0, 2]],
['name' => uniqid(), 'email' => 'test3@test.com', 'exclusions' => [1]],
]],
];
});
// Valid list where a solution is possible
dataset('valid participants list', function () {
return [
[[
['name' => uniqid(), 'email' => 'test@test.com', 'exclusions' => []],
['name' => uniqid(), 'email' => 'test2@test.com', 'exclusions' => []],
['name' => uniqid(), 'email' => 'test3@test.com', 'exclusions' => []],
]],
];
});
// Valid list where there's only one solution
dataset('unique participants list', function () {
return [
[
[
['name' => uniqid(), 'email' => 'test@test.com', 'exclusions' => [2]],
['name' => uniqid(), 'email' => 'test2@test.com', 'exclusions' => [0]],
['name' => uniqid(), 'email' => 'test3@test.com', 'exclusions' => [1]],
],
[1, 2, 0]
],
];
});
\ No newline at end of file
<?php
use App\Models\Draw;
use App\Models\Exclusion;
use App\Models\Participant;
it('throws and exception when there\'s no solution', function ($participants) {
DrawHandler::toParticipants($participants);
})->with('invalid participants list')->throws(App\Exceptions\SolverException::class);
it('does not record anything in case of error', function ($participants) {
assertEquals(0, Draw::count());
assertEquals(0, Participant::count());
assertEquals(0, Exclusion::count());
try { DrawHandler::toParticipants($participants); } catch (Exception $e) {}
assertEquals(0, Draw::count());
assertEquals(0, Participant::count());
assertEquals(0, Exclusion::count());
})->with('invalid participants list');
it('does not send emails in case of error', function ($participants) {
Mail::fake();
Mail::assertNothingSent();
try { DrawHandler::toParticipants($participants); } catch (Exception $e) {}
})->with('invalid participants list');
<?php
use App\Mail\OrganizerRecap;
use App\Mail\TargetDrawn;
use App\Models\Draw;
use App\Models\Exclusion;
use App\Models\Participant;
function createDraw ($participants) {
DrawHandler::toParticipants($participants)
->expiresAt(date('Y-m-d', strtotime('+2 days')))
->sendMail('test mail {SANTA} => {TARGET} title', 'test mail {SANTA} => {TARGET} body');
}
it('records new entries in case of success', function ($participants) {
assertEquals(0, Draw::count());
assertEquals(0, Participant::count());
assertEquals(0, Exclusion::count());
createDraw($participants);
$exclusions = array_reduce($participants, function ($sum, $participant) { return $sum + count($participant['exclusions']); });
assertEquals(1, Draw::count());
assertEquals(count($participants), Participant::count());
assertEquals($exclusions, Exclusion::count());
// Carreful, array is 0..n, Db is 1..n
foreach($participants as $idx => $participant) {
assertEquals($participant['name'], Participant::find($idx + 1)->name);
}
})->with('valid participants list');
it('sends emails in case of success', function ($participants) {
Mail::fake();
createDraw($participants);
// Ensure Organizer receives his recap
assertHasMailPushed(OrganizerRecap::class, $participants[0]['email']);
// Ensure Participants receive their own recap
foreach($participants as $participant) {
assertHasMailPushed(TargetDrawn::class, $participant['email']);
}
})->with('valid participants list');
it('sends target name in emails', function ($participants, $targets) {
Mail::fake();
createDraw($participants);
// TODO: assert body
$title = null;
foreach($participants as $idx => $participant) {
assertHasMailPushed(TargetDrawn::class, $participant['email'], function ($m) use (&$title) {
$title = $m->subject;
});
assertStringContainsString('test mail '.$participant['name'].' => '.$participants[$targets[$idx]]['name'].' title', html_entity_decode($title));
}
})->with('unique participants list');
it('stores database crypted and uncryptable entries', function ($participants) {
Mail::fake();
createDraw($participants);
// Ensure Organizer receives his recap
assertHasMailPushed(OrganizerRecap::class, 'test@test.com', function ($m) use (&$link) {
$link = $m->panelLink;
});
// Check data stored are decryptable
$path = parse_url($link, PHP_URL_PATH);
$pathTheorical = parse_url(route('organizerPanel', ['draw' => '%s']), PHP_URL_PATH);
$data = sscanf($path, $pathTheorical);
$draw = Draw::findByHashOrFail($data[0]);
assertNotEquals(0, $draw->participants->count());
foreach ($draw->participants as $participant) {
assertContains($participant->name, array_column($participants, 'name'));
assertContains($participant->email, array_column($participants, 'email'));
}
})->with('valid participants list');
......@@ -10,48 +10,41 @@ use Hashids;
use Illuminate\Support\Facades\URL;
use Mail;
class RequestDearSantaTest extends RequestCase
{
public function testDearSanta(): void
{
Mail::fake();
Mail::assertNothingSent();
$participants = $this->createNewDraw(3);
// For security issues, the key is only sent by mail and never stored
// So fetch it from the mail
$links = [];
Mail::assertSent(function (TargetDrawn $mail) use (&$links) {
return $links[] = $mail->dearSantaLink;
});
$this->assertEquals(count($participants), count($links));
foreach ($links as $id => $link) {
// Get the form page (just to check http code)
$response = $this->get($link);
$this->assertEquals(200, $response->status(), $response->__toString());
$santaId = array_search($id, array_column($participants, 'target'));
$santa = $participants[$santaId];
// Check data stored are decryptable
$path = parse_url($link, PHP_URL_PATH);
$santaTheorical = Participant::findByDearSantaUrlOrFail($path);
$this->assertEquals($santa['name'], $santaTheorical->santa->name);
$this->assertEquals($santa['email'], $santaTheorical->santa->email);
// Try to contact santa
$this->ajaxPost(URL::signedRoute('dearsanta.contact', ['participant' => $santaTheorical->hash]), [
'content' => 'test dearsanta mail content',
])
->assertJson([
'message' => 'Envoyé avec succès !',
])
->assertStatus(200);
$this->assertHasMailPushed(DearSanta::class, $santaTheorical->santa->email);
}
test('a participant can write to their santa', function () {
Mail::fake();
$participants = createNewDraw(3);
// For security issues, the key is only sent by mail and never stored
// So fetch it from the mail
$links = [];
Mail::assertSent(function (TargetDrawn $mail) use (&$links) {
return $links[] = $mail->dearSantaLink;
});
assertEquals(count($participants), count($links));
foreach ($links as $id => $link) {
// Get the form page (just to check http code)
$response = $this->get($link);
assertEquals(200, $response->status(), $response->__toString());
$santaId = array_search($id, array_column($participants, 'target'));
$santa = $participants[$santaId];
// Check data stored are decryptable
$path = parse_url($link, PHP_URL_PATH);
$santaTheorical = Participant::findByDearSantaUrlOrFail($path);
assertEquals($santa['name'], $santaTheorical->santa->name);
assertEquals($santa['email'], $santaTheorical->santa->email);
// Try to contact santa
ajaxPost(URL::signedRoute('dearsanta.contact', ['participant' => $santaTheorical->hash]), [
'content' => 'test dearsanta mail content',
])
->assertJsonStructure(['message'])
->assertStatus(200);
assertHasMailPushed(DearSanta::class, $santaTheorical->santa->email);
}
}
});
\ No newline at end of file
<?php
namespace Tests\Feature;
use App\Mail\TargetDrawn;
use App\Models\Draw;
use App\Models\Participant;
use Crypt;
use Illuminate\Support\Facades\URL;
use Mail;
class RequestOrganizerTest extends RequestCase
{
public function createDrawWithParticipants(int $participants): Draw
{
$this->assertGreaterThan(1, $participants);
$draw = Draw::factory()->create();
$draw->participants()->createMany(
Participant::factory($participants)->make()->toArray()
);
foreach ($draw->participants as $idx => $participant) {
$target = $draw->participants[$idx - 1 >= 0 ? $idx - 1 : $participants - 1];
$participant->target()->save($target);
}
return $draw;
}
public function testSendAgain(): void
{
Mail::fake();
Mail::assertNothingSent();
$draw = $this->createDrawWithParticipants(3);
$participant = $draw->participants->first();
test('the organizer can send again the target drawn email', function () {
Mail::fake();
// Check data can be changed
$path = URL::signedRoute('organizerPanel.changeEmail', [
'draw' => $draw->hash,
'participant' => $participant->id,
]);
$draw = createDrawWithParticipants(3);
$participant = $draw->participants->first();
$this->ajaxPost($path, [
'email' => $participant->email,
])
->assertJson([
'message' => 'Envoyé avec succès !',
])
->assertStatus(200);
// Check data can be changed
$path = URL::signedRoute('organizerPanel.changeEmail', [
'draw' => $draw->hash,
'participant' => $participant->id,
]);
$this->assertHasMailPushed(TargetDrawn::class, $participant->email);
}
ajaxPost($path, ['email' => $participant->email])->assertJsonStructure(['message'])->assertStatus(200);
assertHasMailPushed(TargetDrawn::class, $participant->email);
});
public function testChangeEmail(): void
{
Mail::fake();
Mail::assertNothingSent();
test('the organizer can change a participant\'s email', function () {
Mail::fake();
$draw = $this->createDrawWithParticipants(3);
$participant = $draw->participants->first();
$draw = createDrawWithParticipants(3);
$participant = $draw->participants->first();
// Check data can be changed
$path = URL::signedRoute('organizerPanel.changeEmail', [
'draw' => $draw->hash,
'participant' => $participant->id,
]);
// Check data can be changed
$path = URL::signedRoute('organizerPanel.changeEmail', [
'draw' => $draw->hash,
'participant' => $participant->id,
]);
$this->ajaxPost($path, [
'email' => 'test@test2.com',
])
->assertJson([
'message' => 'Modifié avec succès !',
])
->assertStatus(200);
ajaxPost($path, ['email' => 'test@test2.com'])->assertJsonStructure(['message'])->assertStatus(200);
$before = $participant->email;
$participant = Participant::find($participant->id);
$after = $participant->email;
$before = $participant->email;
$participant = Participant::find($participant->id);
$after = $participant->email;
$this->assertNotEquals($before, $after);
$this->assertEquals('test@test2.com', $after);
assertNotEquals($before, $after);
assertEquals('test@test2.com', $after);
$this->assertHasMailPushed(TargetDrawn::class, $participant->email);
}
}
assertHasMailPushed(TargetDrawn::class, $participant->email);
});
\ No newline at end of file
......@@ -4,49 +4,42 @@ namespace Tests\Feature;
use DrawHandler;
class RequestTest extends RequestCase
{
use \Illuminate\Foundation\Testing\DatabaseMigrations;
use \Illuminate\Foundation\Testing\DatabaseTransactions;
it('handles ajax format', function () {
$mock = DrawHandler::partialMock();
public function testServiceFormat(): void
{
$mock = DrawHandler::partialMock();
$mock->shouldReceive('toParticipants')
->once()
->with([
['name' => 'toto', 'email' => 'test@test.com', 'exclusions' => []],
['name' => 'tata', 'email' => 'test3@test.com', 'exclusions' => [1, 2]],
['name' => 'tutu', 'email' => 'test2@test.com', 'exclusions' => [0]],
])
->andReturnSelf();
$mock->shouldReceive('toParticipants')
->once()
->with([
['name' => 'toto', 'email' => 'test@test.com', 'exclusions' => []],
['name' => 'tata', 'email' => 'test3@test.com', 'exclusions' => [1, 2]],
['name' => 'tutu', 'email' => 'test2@test.com', 'exclusions' => [0]],
])
->andReturnSelf();
$mock->shouldReceive('sendMail')
->once()
->andReturn(true);
$mock->shouldReceive('sendMail')
->once()
->andReturn(true);
$this->ajaxPost('/', [
'participants' => [
[
'name' => 'toto',
'email' => 'test@test.com',
'exclusions' => [],
],
[
'name' => 'tata',
'email' => 'test3@test.com',
'exclusions' => ['1', '2'],
],
[
'name' => 'tutu',
'email' => 'test2@test.com',
'exclusions' => ['0'],
],
ajaxPost('/', [
'participants' => [
[
'name' => 'toto',
'email' => 'test@test.com',
'exclusions' => [],
],
[
'name' => 'tata',
'email' => 'test3@test.com',
'exclusions' => ['1', '2'],
],
[
'name' => 'tutu',
'email' => 'test2@test.com',
'exclusions' => ['0'],
],
'title' => 'test mail title',
'content-email' => 'test mail {SANTA} => {TARGET}',
'data-expiration' => date('Y-m-d', strtotime('+2 days')),
]);
}
}
],
'title' => 'test mail title',
'content-email' => 'test mail {SANTA} => {TARGET}',
'data-expiration' => date('Y-m-d', strtotime('+2 days')),
]);
});
<?php
it('fails if nothing sent', function () {
ajaxPost('/', ['a' => 'b'])
->assertStatus(422)
->assertJsonValidationErrors([
'participants', 'data-expiration', 'title', 'content-email',
]);
});
it('needs at least three names', function () {
ajaxPost('/', ['participants' => [
['name' => 'toto'],
]])
->assertStatus(422)
->assertJsonValidationErrors([
'participants', 'participants.0.email', 'title', 'content-email', 'data-expiration',
]);
ajaxPost('/', ['participants' => [
['name' => 'toto'],
['name' => 'tata'],
]])
->assertStatus(422)
->assertJsonValidationErrors([
'participants', 'participants.0.email', 'participants.1.email',
'title', 'content-email', 'data-expiration',
]);
});
it('fails if names are duplicates', function () {
ajaxPost('/', ['participants' => [
['name' => 'toto'],
['name' => 'toto'],
]])
->assertStatus(422)
->assertJsonValidationErrors([
'participants',
'participants.0.name', 'participants.0.email',
'participants.1.name', 'participants.1.email',
'title', 'content-email', 'data-expiration',
]);
});
it('requires emails', function () {
ajaxPost('/', ['participants' => [
['name' => 'toto'],
['name' => 'tata'],
['name' => 'tutu'],
]])
->assertStatus(422)
->assertJsonValidationErrors([
'participants.0.email', 'participants.1.email', 'participants.2.email',
'title', 'content-email', 'data-expiration',
]);
ajaxPost('/', ['participants' => [
['name' => 'toto'],
['name' => 'tata', 'email' => 'test@test.com'],
['name' => 'tutu'],
]])
->assertStatus(422)
->assertJsonValidationErrors([
'participants.0.email', 'participants.2.email',
'title', 'content-email', 'data-expiration',
]);
});
it('needs valid email format', function () {
ajaxPost('/', ['participants' => [
['name' => 'toto', 'email' => 'invalidformat'],
['name' => 'tata', 'email' => 'test@test.com'],
['name' => 'tutu', 'email' => 'tata@test.com'],
]])
->assertStatus(422)
->assertJsonValidationErrors([
'participants.0.email',
'title', 'content-email', 'data-expiration',
]);
});
it('needs email body', function () {
ajaxPost('/', ['participants' => [
['name' => 'toto', 'email' => 'test@est.com'],
['name' => 'tata', 'email' => 'test@test.com'],
['name' => 'tutu', 'email' => 'test@test.com'],
]])
->assertStatus(422)
->assertJsonValidationErrors([
'title', 'content-email', 'data-expiration',
]);
});
it('fails if exclusion does not exist', function () {
ajaxPost('/', ['participants' => [
['name' => 'toto', 'exclusions' => ['87']],
['name' => 'tata'],
['name' => 'tutu'],
]])
->assertStatus(422)
->assertJsonValidationErrors([
'participants.0.exclusions.0', 'participants.0.email',
'participants.1.email',
'participants.2.email',
]);
});
it('works with valid exclusion', function () {
ajaxPost('/', ['participants' => [
['name' => 'toto', 'exclusions' => ['1']],
['name' => 'tata'],
['name' => 'tutu'],
]])
->assertStatus(422)
->assertJsonValidationErrors([
'participants.0.email',
'participants.1.email',
'participants.2.email',
'title', 'content-email', 'data-expiration',
]);
});
it('fails if the expiration is too soon', function () {
ajaxPost('/', ['participants' => [
['name' => 'toto', 'email' => 'test@test.com'],
['name' => 'tata', 'email' => 'test@test.com'],
['name' => 'tutu', 'email' => 'test@test.com'],
], 'data-expiration' => date('Y-m-d')])
->assertStatus(422)
->assertJsonValidationErrors(['title', 'content-email', 'data-expiration']);
});