Separated laravel app to its own folder (#540)
This commit is contained in:
40
api/tests/Browser/LoginTest.php
Normal file
40
api/tests/Browser/LoginTest.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Tests\Browser\Pages\Home;
|
||||
use Tests\Browser\Pages\Login;
|
||||
|
||||
uses(\Tests\DuskTestCase::class);
|
||||
|
||||
/** @test */
|
||||
it('can login onboarded users', function () {
|
||||
$user = User::factory()->create();
|
||||
$this->createUserWorkspace($user);
|
||||
|
||||
$this->browse(function ($browser) use ($user) {
|
||||
$browser->visit(new Login())
|
||||
->submit($user->email, 'password')
|
||||
->assertPageIs(Home::class);
|
||||
});
|
||||
});
|
||||
|
||||
it('cannot login with invalid credentials', function () {
|
||||
$this->browse(function ($browser) {
|
||||
$browser->visit(new Login())
|
||||
->submit('test@test.app', 'password')
|
||||
->pause(100)
|
||||
->assertSee('These credentials do not match our records.');
|
||||
});
|
||||
});
|
||||
|
||||
it('can log out the user', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->browse(function ($browser) use ($user) {
|
||||
$browser->visit(new Login())
|
||||
->submit($user->email, 'password')
|
||||
->on(new Home())
|
||||
->clickLogout()
|
||||
->assertPageIs(Login::class);
|
||||
});
|
||||
});
|
||||
53
api/tests/Browser/Pages/Home.php
Normal file
53
api/tests/Browser/Pages/Home.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Pages;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
|
||||
class Home extends Page
|
||||
{
|
||||
/**
|
||||
* Get the URL for the page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url()
|
||||
{
|
||||
return '/home';
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the browser is on the page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function assert(Browser $browser)
|
||||
{
|
||||
$browser->waitForLocation($this->url())->assertPathIs($this->url());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element shortcuts for the page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function elements()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on the log out link.
|
||||
*
|
||||
* @param \Laravel\Dusk\Browser $browser
|
||||
* @return void
|
||||
*/
|
||||
public function clickLogout($browser)
|
||||
{
|
||||
$browser->click('@nav-dropdown-button')
|
||||
->waitFor('@nav-dropdown')
|
||||
->waitForText('Logout')
|
||||
->clickLink('Logout')
|
||||
->pause(100);
|
||||
}
|
||||
}
|
||||
40
api/tests/Browser/Pages/HomePage.php
Normal file
40
api/tests/Browser/Pages/HomePage.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Pages;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
|
||||
class HomePage extends Page
|
||||
{
|
||||
/**
|
||||
* Get the URL for the page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url()
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the browser is on the page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function assert(Browser $browser)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element shortcuts for the page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function elements()
|
||||
{
|
||||
return [
|
||||
'@element' => '#selector',
|
||||
];
|
||||
}
|
||||
}
|
||||
32
api/tests/Browser/Pages/Login.php
Normal file
32
api/tests/Browser/Pages/Login.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Pages;
|
||||
|
||||
class Login extends Page
|
||||
{
|
||||
/**
|
||||
* Get the URL for the page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url()
|
||||
{
|
||||
return '/login';
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit the form with the given credentials.
|
||||
*
|
||||
* @param \Laravel\Dusk\Browser $browser
|
||||
* @param string $email
|
||||
* @param string $password
|
||||
* @return void
|
||||
*/
|
||||
public function submit($browser, $email, $password)
|
||||
{
|
||||
$browser->type('email', $email)
|
||||
->type('password', $password)
|
||||
->press('@btn_login')
|
||||
->pause(500);
|
||||
}
|
||||
}
|
||||
38
api/tests/Browser/Pages/Onboarding.php
Normal file
38
api/tests/Browser/Pages/Onboarding.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Pages;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
|
||||
class Onboarding extends Page
|
||||
{
|
||||
/**
|
||||
* Get the URL for the page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url()
|
||||
{
|
||||
return '/onboarding';
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the browser is on the page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function assert(Browser $browser)
|
||||
{
|
||||
$browser->waitForLocation($this->url())->assertPathIs($this->url());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element shortcuts for the page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function elements()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
31
api/tests/Browser/Pages/Page.php
Normal file
31
api/tests/Browser/Pages/Page.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Pages;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Laravel\Dusk\Page as BasePage;
|
||||
|
||||
abstract class Page extends BasePage
|
||||
{
|
||||
/**
|
||||
* Assert that the browser is on the page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function assert(Browser $browser)
|
||||
{
|
||||
$browser->assertPathIs($this->url());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the global element shortcuts for the site.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function siteElements()
|
||||
{
|
||||
return [
|
||||
'@element' => '#selector',
|
||||
];
|
||||
}
|
||||
}
|
||||
32
api/tests/Browser/Pages/Register.php
Normal file
32
api/tests/Browser/Pages/Register.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Pages;
|
||||
|
||||
class Register extends Page
|
||||
{
|
||||
/**
|
||||
* Get the URL for the page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url()
|
||||
{
|
||||
return '/register';
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit the form with the given data.
|
||||
*
|
||||
* @param \Laravel\Dusk\Browser $browser
|
||||
* @return void
|
||||
*/
|
||||
public function submit($browser, array $data = [])
|
||||
{
|
||||
foreach ($data as $key => $value) {
|
||||
$browser->type($key, $value);
|
||||
}
|
||||
|
||||
$browser->press('Register')
|
||||
->pause(1000);
|
||||
}
|
||||
}
|
||||
72
api/tests/Browser/RegisterTest.php
Normal file
72
api/tests/Browser/RegisterTest.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Pages\Onboarding;
|
||||
use Tests\Browser\Pages\Register;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class RegisterTest extends DuskTestCase
|
||||
{
|
||||
use DatabaseMigrations;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setup();
|
||||
|
||||
static::closeAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick Random option from custom select
|
||||
*
|
||||
* @throws \Facebook\WebDriver\Exception\TimeOutException
|
||||
*/
|
||||
public function selectHearAboutUsReason(Browser $browser)
|
||||
{
|
||||
$browser->waitFor('@hear_about_us')
|
||||
->click('@hear_about_us')
|
||||
->waitFor('@hear_about_us_dropdown');
|
||||
$options = $browser->elements('@hear_about_us_option');
|
||||
shuffle($options);
|
||||
$options[0]->click();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function register_with_valid_data()
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->visit(new Register());
|
||||
$this->selectHearAboutUsReason($browser);
|
||||
$browser->submit([
|
||||
'name' => 'Test User',
|
||||
'email' => 'testuser@test.test',
|
||||
'password' => 'password',
|
||||
'password_confirmation' => 'password',
|
||||
])
|
||||
->assertPageIs(Onboarding::class);
|
||||
});
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function can_not_register_with_the_same_twice()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->browse(function (Browser $browser) use ($user) {
|
||||
$browser->visit(new Register());
|
||||
$this->selectHearAboutUsReason($browser);
|
||||
$browser->submit([
|
||||
'name' => 'Test User',
|
||||
'email' => $user->email,
|
||||
'password' => 'password',
|
||||
'password_confirmation' => 'password',
|
||||
])
|
||||
->pause(3000)
|
||||
->assertSee('The email has already been taken.');
|
||||
});
|
||||
}
|
||||
}
|
||||
18
api/tests/Browser/WelcomeTest.php
Normal file
18
api/tests/Browser/WelcomeTest.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class WelcomeTest extends DuskTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function basic_test()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$browser->visit('/')
|
||||
->waitFor('@title', 1)
|
||||
->assertSee('Forms for Notion');
|
||||
});
|
||||
}
|
||||
}
|
||||
2
api/tests/Browser/console/.gitignore
vendored
Normal file
2
api/tests/Browser/console/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
2
api/tests/Browser/screenshots/.gitignore
vendored
Normal file
2
api/tests/Browser/screenshots/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
2
api/tests/Browser/source/.gitignore
vendored
Normal file
2
api/tests/Browser/source/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
22
api/tests/CreatesApplication.php
Normal file
22
api/tests/CreatesApplication.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
|
||||
trait CreatesApplication
|
||||
{
|
||||
/**
|
||||
* Creates the application.
|
||||
*
|
||||
* @return \Illuminate\Foundation\Application
|
||||
*/
|
||||
public function createApplication()
|
||||
{
|
||||
$app = require __DIR__.'/../bootstrap/app.php';
|
||||
|
||||
$app->make(Kernel::class)->bootstrap();
|
||||
|
||||
return $app;
|
||||
}
|
||||
}
|
||||
61
api/tests/DuskTestCase.php
Normal file
61
api/tests/DuskTestCase.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Facebook\WebDriver\Chrome\ChromeOptions;
|
||||
use Facebook\WebDriver\Remote\DesiredCapabilities;
|
||||
use Facebook\WebDriver\Remote\RemoteWebDriver;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Laravel\Dusk\Browser;
|
||||
use Laravel\Dusk\Page;
|
||||
use Laravel\Dusk\TestCase as BaseTestCase;
|
||||
|
||||
Browser::macro('assertPageIs', function ($page) {
|
||||
if (! $page instanceof Page) {
|
||||
$page = new $page();
|
||||
}
|
||||
|
||||
// waiting for location before asserting, because window.location.pathname may be updated asynchronously
|
||||
return $this->waitForLocation($page->url())->assertPathIs($page->url());
|
||||
});
|
||||
|
||||
abstract class DuskTestCase extends BaseTestCase
|
||||
{
|
||||
use CreatesApplication;
|
||||
use DatabaseMigrations;
|
||||
use TestHelpers;
|
||||
|
||||
/**
|
||||
* Prepare for Dusk test execution.
|
||||
*
|
||||
* @beforeClass
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function prepare()
|
||||
{
|
||||
static::startChromeDriver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the RemoteWebDriver instance.
|
||||
*
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
|
||||
*/
|
||||
protected function driver()
|
||||
{
|
||||
$options = (new ChromeOptions())->addArguments([
|
||||
'--disable-gpu',
|
||||
'--headless',
|
||||
'--window-size=1920,1080',
|
||||
]);
|
||||
|
||||
return RemoteWebDriver::create(
|
||||
'http://localhost:9515',
|
||||
DesiredCapabilities::chrome()->setCapability(
|
||||
ChromeOptions::CAPABILITY,
|
||||
$options
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
305
api/tests/Feature/Forms/AnswerFormTest.php
Normal file
305
api/tests/Feature/Forms/AnswerFormTest.php
Normal file
@@ -0,0 +1,305 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Forms\Form;
|
||||
use Tests\Helpers\FormSubmissionDataFactory;
|
||||
|
||||
it('can answer a form', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
// TODO: generate random response given a form and un-skip
|
||||
})->skip('Need to finish writing a class to generated random responses');
|
||||
|
||||
it('can submit form if close date is in future', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'closes_at' => \Carbon\Carbon::now()->addDays(1)->toDateTimeString(),
|
||||
]);
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can not submit closed form', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'closes_at' => \Carbon\Carbon::now()->subDays(1)->toDateTimeString(),
|
||||
]);
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertStatus(403);
|
||||
});
|
||||
|
||||
it('can submit form till max submissions count is not reached at limit', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'max_submissions_count' => 3,
|
||||
]);
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form);
|
||||
|
||||
// Can submit form
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
}
|
||||
|
||||
// Now, can not submit form, Because it's reached at submission limit
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertStatus(403);
|
||||
});
|
||||
|
||||
it('can not open draft form', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'visibility' => 'draft',
|
||||
]);
|
||||
|
||||
$this->getJson(route('forms.show', $form->slug))
|
||||
->assertStatus(404);
|
||||
});
|
||||
|
||||
it('can not submit draft form', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'visibility' => 'draft',
|
||||
]);
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertStatus(403);
|
||||
});
|
||||
|
||||
it('can not submit visibility closed form', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'visibility' => 'closed',
|
||||
]);
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertStatus(403);
|
||||
});
|
||||
|
||||
it('can not submit form with past dates', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$submissionData = [];
|
||||
$form->properties = collect($form->properties)->map(function ($property) use (&$submissionData) {
|
||||
if (in_array($property['type'], ['date'])) {
|
||||
$property['disable_past_dates'] = true;
|
||||
$submissionData[$property['id']] = now()->subDays(4)->format('Y-m-d');
|
||||
}
|
||||
|
||||
return $property;
|
||||
})->toArray();
|
||||
$form->update();
|
||||
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, $submissionData);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertStatus(422)
|
||||
->assertJson([
|
||||
'message' => 'The Date must be a date after yesterday.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can not submit form with future dates', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$submissionData = [];
|
||||
$form->properties = collect($form->properties)->map(function ($property) use (&$submissionData) {
|
||||
if (in_array($property['type'], ['date'])) {
|
||||
$property['disable_future_dates'] = true;
|
||||
$submissionData[$property['id']] = now()->addDays(4)->format('Y-m-d');
|
||||
}
|
||||
|
||||
return $property;
|
||||
})->toArray();
|
||||
$form->update();
|
||||
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, $submissionData);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertStatus(422)
|
||||
->assertJson([
|
||||
'message' => 'The Date must be a date before tomorrow.',
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
it('can submit form with passed custom validation condition', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
$targetField = collect($form->properties)->where('name', 'Number')->first();
|
||||
$condition = [
|
||||
'actions' => [],
|
||||
'conditions' => [
|
||||
'operatorIdentifier' => 'or',
|
||||
'children' => [
|
||||
[
|
||||
'identifier' => $targetField['id'],
|
||||
'value' => [
|
||||
'operator' => 'greater_than',
|
||||
'property_meta' => [
|
||||
'id' => $targetField['id'],
|
||||
'type' => 'number',
|
||||
],
|
||||
'value' => 20,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
$submissionData = [];
|
||||
$validationMessage = 'Number too low';
|
||||
$form->properties = collect($form->properties)->map(function ($property) use (&$submissionData, &$condition, &$validationMessage, $targetField) {
|
||||
if (in_array($property['name'], ['Name'])) {
|
||||
$property['validation'] = ['error_conditions' => $condition, 'error_message' => $validationMessage];
|
||||
$submissionData[$targetField['id']] = 100;
|
||||
}
|
||||
return $property;
|
||||
})->toArray();
|
||||
|
||||
$form->update();
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, $submissionData);
|
||||
|
||||
$response = $this->postJson(route('forms.answer', $form->slug), $formData);
|
||||
$response->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can not submit form with failed custom validation condition', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
$targetField = collect($form->properties)->where('name', 'Email')->first();
|
||||
$condition = [
|
||||
'actions' => [],
|
||||
'conditions' => [
|
||||
'operatorIdentifier' => 'and',
|
||||
'children' => [
|
||||
[
|
||||
'identifier' => $targetField['id'],
|
||||
'value' => [
|
||||
'operator' => 'equals',
|
||||
'property_meta' => [
|
||||
'id' => $targetField['id'],
|
||||
'type' => 'email',
|
||||
],
|
||||
'value' => 'test@gmail.com',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
$submissionData = [];
|
||||
$validationMessage = 'Can only use test@gmail.com';
|
||||
$form->properties = collect($form->properties)->map(function ($property) use (&$submissionData, &$condition, &$validationMessage, &$targetField) {
|
||||
if (in_array($property['name'], ['Name'])) {
|
||||
$property['validation'] = ['error_conditions' => $condition, 'error_message' => $validationMessage];
|
||||
$submissionData[$targetField['id']] = 'fail@gmail.com';
|
||||
}
|
||||
return $property;
|
||||
})->toArray();
|
||||
|
||||
$form->update();
|
||||
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, $submissionData);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertStatus(422)
|
||||
->assertJson([
|
||||
'message' => $validationMessage,
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
it('can validate form answer with precognition', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
$properties = $form->properties;
|
||||
$properties[0]['required'] = true;
|
||||
$properties[3]['required'] = true;
|
||||
$properties[6]['required'] = true;
|
||||
$properties[9]['required'] = true;
|
||||
|
||||
$form->properties = $properties;
|
||||
$form->update();
|
||||
|
||||
// Empty submission data should fail validation, with all 4 required fields
|
||||
$response = $this->postJson(route('forms.answer', $form->slug), []);
|
||||
$errors = $response->json()['errors'];
|
||||
$this->assertEquals(sizeof($errors), 4);
|
||||
$response->assertStatus(422);
|
||||
|
||||
// Fill in data for only Name.
|
||||
$submissionData = [];
|
||||
foreach ($properties as $property) {
|
||||
if ($property['name'] == 'Name') {
|
||||
$submissionData[$property['id']] = 'Name';
|
||||
} else {
|
||||
$submissionData[$property['id']] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Select only first 3 fields for precognition validation
|
||||
$validateOnlyFields = [
|
||||
$properties[0]['id'],
|
||||
$properties[1]['id'],
|
||||
$properties[2]['id']
|
||||
];
|
||||
|
||||
$precognitionValidateOnly = implode(',', $validateOnlyFields);
|
||||
|
||||
// Partial submission data should pass validation for the precognition only fields.
|
||||
$response = $this->withPrecognition()->withHeaders([
|
||||
'Precognition-Validate-Only' => $precognitionValidateOnly
|
||||
])
|
||||
->postJson(route('forms.answer', $form->slug), $submissionData);
|
||||
|
||||
$response->assertSuccessfulPrecognition();
|
||||
|
||||
|
||||
// Select only next fields for precognition validation
|
||||
$validateOnlyFields = $validateOnlyFields = [
|
||||
$properties[3]['id'],
|
||||
$properties[4]['id'],
|
||||
$properties[5]['id']
|
||||
];
|
||||
$precognitionValidateOnly = implode(',', $validateOnlyFields);
|
||||
|
||||
// Partial submission data should fail validation, but for only one required field specified for precognition validation.
|
||||
$response = $this->withPrecognition()->withHeaders([
|
||||
'Precognition-Validate-Only' => $precognitionValidateOnly
|
||||
])
|
||||
->postJson(route('forms.answer', $form->slug), $submissionData);
|
||||
$errors = $response->json()['errors'];
|
||||
$this->assertEquals(sizeof($errors), 1);
|
||||
$response->assertStatus(422);
|
||||
});
|
||||
48
api/tests/Feature/Forms/CleanDatabaseTest.php
Normal file
48
api/tests/Feature/Forms/CleanDatabaseTest.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
it('check form statistic for views & submissions counts', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, []);
|
||||
|
||||
// Create 10 views & submissions (in the past of 1 day so that it's cleaned)
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
$submission = $form->submissions()->create();
|
||||
$submission->created_at = now()->subDay();
|
||||
$submission->save();
|
||||
$view = $form->views()->create();
|
||||
$view->created_at = now()->subDay();
|
||||
$view->save();
|
||||
}
|
||||
|
||||
// Create a submission & a view for another date
|
||||
$submission = $form->submissions()->create();
|
||||
$submission->created_at = now()->subDays(2);
|
||||
$submission->save();
|
||||
$view = $form->views()->create();
|
||||
$view->created_at = now()->subDays(2);
|
||||
$view->save();
|
||||
|
||||
// Run Command
|
||||
Artisan::call('forms:database-cleanup');
|
||||
|
||||
// Create 5 views & submissions
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$form->views()->create();
|
||||
$form->submissions()->create();
|
||||
}
|
||||
|
||||
// Now check counters
|
||||
$statistics = $form->statistics()->get();
|
||||
expect($form->views_count)->toBe(16);
|
||||
expect($form->submissions_count)->toBe(16);
|
||||
expect($form->views()->count())->toBe(5);
|
||||
expect($form->submissions()->count())->toBe(16);
|
||||
expect(count($statistics))->toBe(2); // 1 per day for 2 different dates
|
||||
expect($statistics[0]['date'])->toBe(now()->subDays(2)->toDateString());
|
||||
expect($statistics[0]['data'])->toBe(['views' => 1, 'submissions' => 0]);
|
||||
expect($statistics[1]['date'])->toBe(now()->subDay()->toDateString());
|
||||
expect($statistics[1]['data'])->toBe(['views' => 10, 'submissions' => 0]);
|
||||
});
|
||||
144
api/tests/Feature/Forms/ConfirmationEmailTest.php
Normal file
144
api/tests/Feature/Forms/ConfirmationEmailTest.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
use App\Mail\Forms\SubmissionConfirmationMail;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
it('creates confirmation emails with the submitted data', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
$integrationData = $this->createFormIntegration('submission_confirmation', $form->id, [
|
||||
'respondent_email' => true,
|
||||
'notifications_include_submission' => true,
|
||||
'notification_sender' => 'Custom Sender',
|
||||
'notification_subject' => 'Test subject',
|
||||
'notification_body' => 'Test body',
|
||||
]);
|
||||
|
||||
$formData = [
|
||||
collect($form->properties)->first(function ($property) {
|
||||
return $property['type'] == 'email';
|
||||
})['id'] => 'test@test.com',
|
||||
];
|
||||
$event = new \App\Events\Forms\FormSubmitted($form, $formData);
|
||||
$mailable = new SubmissionConfirmationMail($event, $integrationData);
|
||||
$mailable->assertSeeInHtml('Test body')
|
||||
->assertSeeInHtml('As a reminder, here are your answers:')
|
||||
->assertSeeInHtml('You are receiving this email because you answered the form:');
|
||||
});
|
||||
|
||||
it('creates confirmation emails without the submitted data', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
$integrationData = $this->createFormIntegration('submission_confirmation', $form->id, [
|
||||
'respondent_email' => true,
|
||||
'notifications_include_submission' => false,
|
||||
'notification_sender' => 'Custom Sender',
|
||||
'notification_subject' => 'Test subject',
|
||||
'notification_body' => 'Test body',
|
||||
]);
|
||||
|
||||
$formData = [
|
||||
collect($form->properties)->first(function ($property) {
|
||||
return $property['type'] == 'email';
|
||||
})['id'] => 'test@test.com',
|
||||
];
|
||||
$event = new \App\Events\Forms\FormSubmitted($form, $formData);
|
||||
$mailable = new SubmissionConfirmationMail($event, $integrationData);
|
||||
$mailable->assertSeeInHtml('Test body')
|
||||
->assertDontSeeInHtml('As a reminder, here are your answers:')
|
||||
->assertSeeInHtml('You are receiving this email because you answered the form:');
|
||||
});
|
||||
|
||||
it('sends a confirmation email if needed', function () {
|
||||
$user = $this->actingAsProUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$this->createFormIntegration('submission_confirmation', $form->id, [
|
||||
'respondent_email' => true,
|
||||
'notifications_include_submission' => true,
|
||||
'notification_sender' => 'Custom Sender',
|
||||
'notification_subject' => 'Test subject',
|
||||
'notification_body' => 'Test body',
|
||||
]);
|
||||
|
||||
$emailProperty = collect($form->properties)->first(function ($property) {
|
||||
return $property['type'] == 'email';
|
||||
});
|
||||
$formData = [
|
||||
$emailProperty['id'] => 'test@test.com',
|
||||
];
|
||||
|
||||
Mail::fake();
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
|
||||
Mail::assertQueued(
|
||||
SubmissionConfirmationMail::class,
|
||||
function (SubmissionConfirmationMail $mail) {
|
||||
return $mail->hasTo('test@test.com');
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('does not send a confirmation email if not needed', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
$emailProperty = collect($form->properties)->first(function ($property) {
|
||||
return $property['type'] == 'email';
|
||||
});
|
||||
$formData = [
|
||||
$emailProperty['id'] => 'test@test.com',
|
||||
];
|
||||
|
||||
Mail::fake();
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
|
||||
Mail::assertNotQueued(
|
||||
SubmissionConfirmationMail::class,
|
||||
function (SubmissionConfirmationMail $mail) {
|
||||
return $mail->hasTo('test@test.com');
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('does send a confirmation email even when reply to is broken', function () {
|
||||
$user = $this->actingAsProUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
$integrationData = $this->createFormIntegration('submission_confirmation', $form->id, [
|
||||
'respondent_email' => true,
|
||||
'notifications_include_submission' => true,
|
||||
'notification_sender' => 'Custom Sender',
|
||||
'notification_subject' => 'Test subject',
|
||||
'notification_body' => 'Test body',
|
||||
'confirmation_reply_to' => ''
|
||||
]);
|
||||
|
||||
$emailProperty = collect($form->properties)->first(function ($property) {
|
||||
return $property['type'] == 'email';
|
||||
});
|
||||
$formData = [
|
||||
$emailProperty['id'] => 'test@test.com',
|
||||
];
|
||||
$event = new \App\Events\Forms\FormSubmitted($form, $formData);
|
||||
$mailable = new SubmissionConfirmationMail($event, $integrationData);
|
||||
$mailable->assertSeeInHtml('Test body')
|
||||
->assertSeeInHtml('As a reminder, here are your answers:')
|
||||
->assertSeeInHtml('You are receiving this email because you answered the form:')
|
||||
->assertHasReplyTo($user->email); // Even though reply to is wrong, it should use the user's email
|
||||
});
|
||||
28
api/tests/Feature/Forms/CreateDynamicSelectOptionTest.php
Normal file
28
api/tests/Feature/Forms/CreateDynamicSelectOptionTest.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Tests\Helpers\FormSubmissionDataFactory;
|
||||
|
||||
it('can submit form with dyanamic select option', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$selectionsPreData = [];
|
||||
$form->properties = collect($form->properties)->map(function ($property) use (&$selectionsPreData) {
|
||||
if (in_array($property['type'], ['select', 'multi_select'])) {
|
||||
$property['allow_creation'] = true;
|
||||
$selectionsPreData[$property['id']] = ($property['type'] == 'select') ? 'New single select - '.time() : ['New multi select - '.time()];
|
||||
}
|
||||
|
||||
return $property;
|
||||
})->toArray();
|
||||
$form->update();
|
||||
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, $selectionsPreData);
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
});
|
||||
20
api/tests/Feature/Forms/FormCaptchaTest.php
Normal file
20
api/tests/Feature/Forms/FormCaptchaTest.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
it('create form with captcha and raise validation issue', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'use_captcha' => true,
|
||||
]);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), [])
|
||||
->assertStatus(422)
|
||||
->assertJson([
|
||||
'message' => 'Please complete the captcha.',
|
||||
'errors' => [
|
||||
'h-captcha-response' => [
|
||||
'Please complete the captcha.',
|
||||
],
|
||||
],
|
||||
]);
|
||||
});
|
||||
28
api/tests/Feature/Forms/FormIntegrationEventTest.php
Normal file
28
api/tests/Feature/Forms/FormIntegrationEventTest.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
it('can fetch form integration events', function () {
|
||||
$user = $this->actingAsProUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$data = [
|
||||
'status' => true,
|
||||
'integration_id' => 'email',
|
||||
'logic' => null,
|
||||
'settings' => [
|
||||
'notification_emails' => 'test@test.com',
|
||||
'notification_reply_to' => null
|
||||
]
|
||||
];
|
||||
|
||||
$response = $this->postJson(route('open.forms.integration.create', $form->id), $data)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form Integration was created.'
|
||||
]);
|
||||
|
||||
$this->getJson(route('open.forms.integrations.events', [$form->id, $response->json('form_integration.id')]))
|
||||
->assertSuccessful()
|
||||
->assertJsonCount(0);
|
||||
});
|
||||
42
api/tests/Feature/Forms/FormIntegrationTest.php
Normal file
42
api/tests/Feature/Forms/FormIntegrationTest.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
it('can CRUD form integration', function () {
|
||||
$user = $this->actingAsProUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$data = [
|
||||
'status' => true,
|
||||
'integration_id' => 'email',
|
||||
'logic' => null,
|
||||
'settings' => [
|
||||
'notification_emails' => 'test@test.com',
|
||||
'notification_reply_to' => null
|
||||
]
|
||||
];
|
||||
|
||||
$response = $this->postJson(route('open.forms.integration.create', $form->id), $data)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form Integration was created.'
|
||||
]);
|
||||
|
||||
$this->getJson(route('open.forms.integrations', $form->id))
|
||||
->assertSuccessful()
|
||||
->assertJsonCount(1);
|
||||
|
||||
$this->putJson(route('open.forms.integration.update', [$form->id, $response->json('form_integration.id')]), $data)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form Integration was updated.'
|
||||
]);
|
||||
|
||||
$this->deleteJson(route('open.forms.integration.destroy', [$form->id, $response->json('form_integration.id')]), $data)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form Integration was deleted.'
|
||||
]);
|
||||
});
|
||||
115
api/tests/Feature/Forms/FormLogicTest.php
Normal file
115
api/tests/Feature/Forms/FormLogicTest.php
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Testing\Fluent\AssertableJson;
|
||||
|
||||
it('create form with logic', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'properties' => [
|
||||
[
|
||||
'id' => 'title',
|
||||
'name' => 'Name',
|
||||
'type' => 'title',
|
||||
'hidden' => false,
|
||||
'required' => true,
|
||||
'logic' => [
|
||||
'conditions' => [
|
||||
'operatorIdentifier' => 'and',
|
||||
'children' => [
|
||||
[
|
||||
'identifier' => 'email',
|
||||
'value' => [
|
||||
'operator' => 'is_empty',
|
||||
'property_meta' => [
|
||||
'id' => '93ea3198-353f-440b-8dc9-2ac9a7bee124',
|
||||
'type' => 'email',
|
||||
],
|
||||
'value' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'actions' => ['make-it-optional'],
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->getJson(route('forms.show', $form->slug))
|
||||
->assertSuccessful()
|
||||
->assertJson(function (AssertableJson $json) use ($form) {
|
||||
return $json->where('id', $form->id)
|
||||
->where('properties', function ($values) {
|
||||
return count($values[0]['logic']) > 0;
|
||||
})
|
||||
->etc();
|
||||
});
|
||||
|
||||
// Should submit form
|
||||
$forData = ['93ea3198-353f-440b-8dc9-2ac9a7bee124' => ''];
|
||||
$this->postJson(route('forms.answer', $form->slug), $forData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('create form with multi select logic', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'properties' => [
|
||||
[
|
||||
'id' => 'title',
|
||||
'name' => 'Name',
|
||||
'type' => 'title',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
'logic' => [
|
||||
'conditions' => [
|
||||
'operatorIdentifier' => 'and',
|
||||
'children' => [
|
||||
[
|
||||
'identifier' => 'multi_select',
|
||||
'value' => [
|
||||
'operator' => 'contains',
|
||||
'property_meta' => [
|
||||
'id' => '93ea3198-353f-440b-8dc9-2ac9a7bee124',
|
||||
'type' => 'multi_select',
|
||||
],
|
||||
'value' => 'One',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'actions' => ['require-answer'],
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->getJson(route('forms.show', $form->slug))
|
||||
->assertSuccessful()
|
||||
->assertJson(function (AssertableJson $json) use ($form) {
|
||||
return $json->where('id', $form->id)
|
||||
->where('properties', function ($values) {
|
||||
return count($values[0]['logic']) > 0;
|
||||
})
|
||||
->etc();
|
||||
});
|
||||
|
||||
// Should submit form
|
||||
$forData = ['93ea3198-353f-440b-8dc9-2ac9a7bee124' => ['One']];
|
||||
$this->postJson(route('forms.answer', $form->slug), $forData)
|
||||
->assertStatus(422)
|
||||
->assertJson([
|
||||
'message' => 'The Name field is required.',
|
||||
'errors' => [
|
||||
'title' => [
|
||||
'The Name field is required.',
|
||||
],
|
||||
],
|
||||
]);
|
||||
});
|
||||
96
api/tests/Feature/Forms/FormPasswordTest.php
Normal file
96
api/tests/Feature/Forms/FormPasswordTest.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Testing\Fluent\AssertableJson;
|
||||
use Tests\Helpers\FormSubmissionDataFactory;
|
||||
|
||||
beforeEach(function () {
|
||||
$this->password = '12345';
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$this->form = $this->createForm($user, $workspace, [
|
||||
'password' => $this->password,
|
||||
]);
|
||||
$this->formData = FormSubmissionDataFactory::generateSubmissionData($this->form);
|
||||
});
|
||||
|
||||
it('can allow form owner to access and submit form without password', function () {
|
||||
// As Form Owner so can access form without password
|
||||
$this->getJson(route('forms.show', $this->form->slug))
|
||||
->assertSuccessful()
|
||||
->assertJson(function (AssertableJson $json) {
|
||||
return $json->where('id', $this->form->id)
|
||||
->where('has_password', true)
|
||||
->where('is_password_protected', false)
|
||||
->etc();
|
||||
});
|
||||
|
||||
// As Form Owner so can submit form without password
|
||||
$this->postJson(route('forms.answer', $this->form->slug), $this->formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can not access form without password for guest user', function () {
|
||||
$this->actingAsGuest();
|
||||
|
||||
$this->getJson(route('forms.show', $this->form->slug))
|
||||
->assertSuccessful()
|
||||
->assertJson(function (AssertableJson $json) {
|
||||
return $json->where('id', $this->form->id)
|
||||
->where('has_password', true)
|
||||
->where('is_password_protected', true)
|
||||
->etc();
|
||||
});
|
||||
});
|
||||
|
||||
it('can not submit form without password for guest user', function () {
|
||||
$this->actingAsGuest();
|
||||
|
||||
$this->postJson(route('forms.answer', $this->form->slug), $this->formData)
|
||||
->assertStatus(403)
|
||||
->assertJson([
|
||||
'status' => 'Unauthorized',
|
||||
'message' => 'Form is protected.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can not submit form with wrong password for guest user', function () {
|
||||
$this->actingAsGuest();
|
||||
|
||||
$this->withHeaders(['form-password' => hash('sha256', 'WRONGPASSWORD')])
|
||||
->postJson(route('forms.answer', $this->form->slug), $this->formData)
|
||||
->assertStatus(403)
|
||||
->assertJson([
|
||||
'status' => 'Unauthorized',
|
||||
'message' => 'Form is protected.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can access form with right password for guest user', function () {
|
||||
$this->actingAsGuest();
|
||||
|
||||
$this->withHeaders(['form-password' => hash('sha256', $this->password)])
|
||||
->getJson(route('forms.show', $this->form->slug))
|
||||
->assertSuccessful()
|
||||
->assertJson(function (AssertableJson $json) {
|
||||
return $json->where('id', $this->form->id)
|
||||
->where('has_password', true)
|
||||
->where('is_password_protected', false)
|
||||
->etc();
|
||||
});
|
||||
});
|
||||
|
||||
it('can submit form with right password for guest user', function () {
|
||||
$this->actingAsGuest();
|
||||
|
||||
$this->withHeaders(['form-password' => hash('sha256', $this->password)])
|
||||
->postJson(route('forms.answer', $this->form->slug), $this->formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
});
|
||||
201
api/tests/Feature/Forms/FormPropertyLogicTest.php
Normal file
201
api/tests/Feature/Forms/FormPropertyLogicTest.php
Normal file
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
use App\Rules\FormPropertyLogicRule;
|
||||
|
||||
it('can validate form logic rules for actions', function () {
|
||||
$rules = [
|
||||
'properties.*.logic' => ['array', 'nullable', new FormPropertyLogicRule()],
|
||||
];
|
||||
|
||||
$data = [
|
||||
'properties' => [
|
||||
[
|
||||
'id' => 'title',
|
||||
'name' => 'Name',
|
||||
'type' => 'title',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
'logic' => [
|
||||
'conditions' => null,
|
||||
'actions' => [],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
$validatorObj = $this->app['validator']->make($data, $rules);
|
||||
$this->assertTrue($validatorObj->passes());
|
||||
|
||||
$data = [
|
||||
'properties' => [
|
||||
[
|
||||
'id' => 'title',
|
||||
'name' => 'Name',
|
||||
'type' => 'title',
|
||||
'hidden' => true,
|
||||
'required' => false,
|
||||
'logic' => [
|
||||
'conditions' => [
|
||||
'operatorIdentifier' => 'and',
|
||||
'children' => [
|
||||
[
|
||||
'identifier' => 'title',
|
||||
'value' => [
|
||||
'operator' => 'equals',
|
||||
'property_meta' => [
|
||||
'id' => 'title',
|
||||
'type' => 'text',
|
||||
],
|
||||
'value' => 'TEST',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'actions' => ['hide-block'],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
$validatorObj = $this->app['validator']->make($data, $rules);
|
||||
$this->assertFalse($validatorObj->passes());
|
||||
expect($validatorObj->errors()->messages()['properties.0.logic'][0])->toBe('The logic actions for Name are not valid.');
|
||||
|
||||
$data = [
|
||||
'properties' => [
|
||||
[
|
||||
'id' => 'text',
|
||||
'name' => 'Custom Test',
|
||||
'type' => 'nf-text',
|
||||
'logic' => [
|
||||
'conditions' => [
|
||||
'operatorIdentifier' => 'and',
|
||||
'children' => [
|
||||
[
|
||||
'identifier' => 'title',
|
||||
'value' => [
|
||||
'operator' => 'equals',
|
||||
'property_meta' => [
|
||||
'id' => 'title',
|
||||
'type' => 'text',
|
||||
],
|
||||
'value' => 'TEST',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'actions' => ['require-answer'],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
$validatorObj = $this->app['validator']->make($data, $rules);
|
||||
$this->assertFalse($validatorObj->passes());
|
||||
expect($validatorObj->errors()->messages()['properties.0.logic'][0])->toBe('The logic actions for Custom Test are not valid.');
|
||||
});
|
||||
|
||||
it('can validate form logic rules for conditions', function () {
|
||||
$rules = [
|
||||
'properties.*.logic' => ['array', 'nullable', new FormPropertyLogicRule()],
|
||||
];
|
||||
|
||||
$data = [
|
||||
'properties' => [
|
||||
[
|
||||
'id' => 'title',
|
||||
'name' => 'Name',
|
||||
'type' => 'text',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
'logic' => [
|
||||
'conditions' => [
|
||||
'operatorIdentifier' => 'and',
|
||||
'children' => [
|
||||
[
|
||||
'identifier' => 'title',
|
||||
'value' => [
|
||||
'operator' => 'equals',
|
||||
'property_meta' => [
|
||||
'id' => 'title',
|
||||
'type' => 'text',
|
||||
],
|
||||
'value' => 'TEST',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'actions' => ['hide-block'],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$validatorObj = $this->app['validator']->make($data, $rules);
|
||||
$this->assertTrue($validatorObj->passes());
|
||||
|
||||
$data = [
|
||||
'properties' => [
|
||||
[
|
||||
'id' => 'title',
|
||||
'name' => 'Name',
|
||||
'type' => 'text',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
'logic' => [
|
||||
'conditions' => [
|
||||
'operatorIdentifier' => 'and',
|
||||
'children' => [
|
||||
[
|
||||
'identifier' => 'title',
|
||||
'value' => [
|
||||
'operator' => 'starts_with',
|
||||
'property_meta' => [
|
||||
'id' => 'title',
|
||||
'type' => 'text',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'actions' => ['hide-block'],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$validatorObj = $this->app['validator']->make($data, $rules);
|
||||
$this->assertFalse($validatorObj->passes());
|
||||
expect($validatorObj->errors()->messages()['properties.0.logic'][0])->toBe('The logic conditions for Name are not complete. Error detail(s): missing condition value');
|
||||
|
||||
$data = [
|
||||
'properties' => [
|
||||
[
|
||||
'id' => 'title',
|
||||
'name' => 'Name',
|
||||
'type' => 'text',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
'logic' => [
|
||||
'conditions' => [
|
||||
'operatorIdentifier' => null,
|
||||
'children' => [
|
||||
[
|
||||
'identifier' => 'title',
|
||||
'value' => [
|
||||
'operator' => 'starts_with',
|
||||
'property_meta' => [
|
||||
'id' => 'title',
|
||||
'type' => 'text',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'actions' => ['hide-block'],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$validatorObj = $this->app['validator']->make($data, $rules);
|
||||
$this->assertFalse($validatorObj->passes());
|
||||
expect($validatorObj->errors()->messages()['properties.0.logic'][0])->toBe('The logic conditions for Name are not complete. Error detail(s): missing operator');
|
||||
});
|
||||
67
api/tests/Feature/Forms/FormStatTest.php
Normal file
67
api/tests/Feature/Forms/FormStatTest.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
it('check formstat chart data', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, []);
|
||||
|
||||
$views = [];
|
||||
$submissions = [];
|
||||
// Create 10 views & submissions for past days
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
$date = now()->subDays($i);
|
||||
$dateString = $date->format('d-m-Y');
|
||||
|
||||
$submission = $form->submissions()->create();
|
||||
$submission->created_at = $date;
|
||||
$submission->save();
|
||||
$view = $form->views()->create();
|
||||
$view->created_at = $date;
|
||||
$view->save();
|
||||
|
||||
$views[$dateString] = isset($views[$dateString]) ? ($views[$dateString] + 1) : 1;
|
||||
$submissions[$dateString] = isset($submissions[$dateString]) ? ($submissions[$dateString] + 1) : 1;
|
||||
}
|
||||
|
||||
// Run Command
|
||||
Artisan::call('forms:database-cleanup');
|
||||
|
||||
// Create 5 views & submissions
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$form->views()->create();
|
||||
$form->submissions()->create();
|
||||
|
||||
$dateString = now()->format('d-m-Y');
|
||||
$views[$dateString] = isset($views[$dateString]) ? ($views[$dateString] + 1) : 1;
|
||||
$submissions[$dateString] = isset($submissions[$dateString]) ? ($submissions[$dateString] + 1) : 1;
|
||||
}
|
||||
|
||||
// Now check chart data
|
||||
$this->getJson(route('open.workspaces.form.stats', [$workspace->id, $form->id]))
|
||||
->assertSuccessful()
|
||||
->assertJson(function (\Illuminate\Testing\Fluent\AssertableJson $json) use ($views, $submissions) {
|
||||
return $json->whereType('views', 'array')
|
||||
->whereType('submissions', 'array')
|
||||
->where('views', function ($values) use ($views) {
|
||||
foreach ($values as $date => $count) {
|
||||
if ((isset($views[$date]) && $views[$date] != $count) || (!isset($views[$date]) && $count != 0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
->where('submissions', function ($values) use ($submissions) {
|
||||
foreach ($values as $date => $count) {
|
||||
if ((isset($submissions[$date]) && $submissions[$date] != $count) || (!isset($submissions[$date]) && $count != 0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
->etc();
|
||||
});
|
||||
});
|
||||
193
api/tests/Feature/Forms/FormTest.php
Normal file
193
api/tests/Feature/Forms/FormTest.php
Normal file
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Testing\Fluent\AssertableJson;
|
||||
|
||||
it('can create a contact form', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->makeForm($user, $workspace);
|
||||
$formData = new \App\Http\Resources\FormResource($form);
|
||||
|
||||
$response = $this->postJson(route('open.forms.store', $formData->toArray(request())))
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form created.',
|
||||
]);
|
||||
|
||||
expect($workspace->forms()->count())->toBe(1);
|
||||
$this->assertDatabaseHas('forms', [
|
||||
'id' => $response->json('form.id'),
|
||||
]);
|
||||
});
|
||||
|
||||
it('can fetch forms', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$this->getJson(route('open.workspaces.forms.index', $workspace->id))
|
||||
->assertSuccessful()
|
||||
->assertJsonCount(3)
|
||||
->assertSuccessful()
|
||||
->assertJsonPath('data.0.id', $form->id)
|
||||
->assertJsonPath('data.0.title', $form->title);
|
||||
});
|
||||
|
||||
it('can fetch a form', function () {
|
||||
$user = $this->actingAsProUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$response = $this->getJson(route('open.forms.show', $form->slug))
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'id' => $form->id,
|
||||
'title' => $form->title
|
||||
]);
|
||||
});
|
||||
|
||||
it('can update a form', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
$newFormData = $this->makeForm($user, $workspace);
|
||||
$form->fill((new \App\Http\Resources\FormResource($newFormData))->toArray(request()));
|
||||
|
||||
$formData = (new \App\Http\Resources\FormResource($form))->toArray(request());
|
||||
|
||||
$this->putJson(route('open.forms.update', $form->id), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form updated.',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('forms', [
|
||||
'id' => $form->id,
|
||||
'title' => $form->title,
|
||||
'description' => $form->description,
|
||||
]);
|
||||
});
|
||||
|
||||
it('can regenerate a form url', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
$newFormData = $this->makeForm($user, $workspace);
|
||||
$form->update([
|
||||
'title' => $newFormData->title,
|
||||
]);
|
||||
$form->generateSlug();
|
||||
$newSlug = $form->slug;
|
||||
|
||||
$this->putJson(route('open.forms.regenerate-link', [$form->id, 'uuid']))
|
||||
->assertSuccessful()
|
||||
->assertJson(function (AssertableJson $json) {
|
||||
return $json->where('type', 'success')
|
||||
->where('form.slug', function ($value) {
|
||||
if (!is_string($value) || (preg_match(
|
||||
'/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/',
|
||||
$value
|
||||
) !== 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
->etc();
|
||||
});
|
||||
|
||||
$this->putJson(route('open.forms.regenerate-link', [$form->id, 'slug']))
|
||||
->assertSuccessful()
|
||||
->assertJson(function (AssertableJson $json) use ($newSlug) {
|
||||
return $json->where('type', 'success')
|
||||
->where('form.slug', function ($slug) use ($newSlug) {
|
||||
return substr($slug, 0, -6) == substr($newSlug, 0, -6);
|
||||
})
|
||||
->etc();
|
||||
});
|
||||
});
|
||||
|
||||
it('can duplicate a form', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$response = $this->postJson(route('open.forms.duplicate', $form->id))
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form successfully duplicated. You are now editing the duplicated version of the form.',
|
||||
]);
|
||||
|
||||
expect($user->forms()->count())->toBe(2);
|
||||
expect($workspace->forms()->count())->toBe(2);
|
||||
$this->assertDatabaseHas('forms', [
|
||||
'id' => $response->json('new_form.id'),
|
||||
'title' => 'Copy of ' . $form->title,
|
||||
'description' => $form->description,
|
||||
]);
|
||||
});
|
||||
|
||||
it('can delete a form', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$this->deleteJson(route('open.forms.destroy', $form->id))
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form was deleted.',
|
||||
]);
|
||||
expect($user->forms()->count())->toBe(0);
|
||||
expect($workspace->forms()->count())->toBe(0);
|
||||
});
|
||||
|
||||
it('can create form with dark mode', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'dark_mode' => 'dark',
|
||||
]);
|
||||
$formData = (new \App\Http\Resources\FormResource($form))->toArray(request());
|
||||
|
||||
$this->postJson(route('open.forms.store', $formData))
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form created.',
|
||||
]);
|
||||
|
||||
$this->getJson(route('forms.show', $form->slug))
|
||||
->assertSuccessful()
|
||||
->assertJson(function (AssertableJson $json) use ($form) {
|
||||
return $json->where('id', $form->id)
|
||||
->where('dark_mode', 'dark')
|
||||
->etc();
|
||||
});
|
||||
});
|
||||
|
||||
it('can create form with custom scripts', function () {
|
||||
$user = $this->actingAsTrialingUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'custom_code' => "<script>console.log('Hello')</script>",
|
||||
]);
|
||||
$formData = (new \App\Http\Resources\FormResource($form))->toArray(request());
|
||||
$this->postJson(route('open.forms.store', $formData))
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form successfully created, but the Non-trial features you used will be disabled when sharing your form:',
|
||||
'form' => ['custom_code' => null]
|
||||
]);
|
||||
|
||||
$this->getJson(route('forms.show', $form->slug))
|
||||
->assertSuccessful()->assertJson([
|
||||
'id' => $form->id,
|
||||
'title' => $form->title,
|
||||
'custom_code' => null
|
||||
]);
|
||||
})->skip(true, 'Trialing custom script form cleaning disabled for now.');
|
||||
41
api/tests/Feature/Forms/FormUpdateTest.php
Normal file
41
api/tests/Feature/Forms/FormUpdateTest.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Tests\Helpers\FormSubmissionDataFactory;
|
||||
|
||||
it('can update form with existing record', function () {
|
||||
$user = $this->actingAsProUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'editable_submissions' => true,
|
||||
]);
|
||||
|
||||
$nameProperty = collect($form->properties)->filter(function ($property) {
|
||||
return $property['name'] == 'Name';
|
||||
})->first();
|
||||
|
||||
$response = $this->postJson(route('forms.answer', $form->slug), [$nameProperty['id'] => 'Testing'])
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
$submissionId = $response->json('submission_id');
|
||||
expect($submissionId)->toBeString();
|
||||
|
||||
if ($submissionId) {
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, ['submission_id' => $submissionId, $nameProperty['id'] => 'Testing Updated']);
|
||||
$response = $this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
$submissionId2 = $response->json('submission_id');
|
||||
expect($submissionId2)->toBeString();
|
||||
expect($submissionId2)->toBe($submissionId);
|
||||
|
||||
$response = $this->getJson(route('forms.fetchSubmission', [$form->slug, $submissionId]))
|
||||
->assertSuccessful();
|
||||
expect($response->json('data.'.$nameProperty['id']))->toBe('Testing Updated');
|
||||
}
|
||||
});
|
||||
37
api/tests/Feature/Forms/FormViewsTest.php
Normal file
37
api/tests/Feature/Forms/FormViewsTest.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
it('can see form without counting view for form owner', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$this->getJson(route('forms.show', $form->slug))
|
||||
->assertSuccessful()
|
||||
->assertJson(function (\Illuminate\Testing\Fluent\AssertableJson $json) use ($form) {
|
||||
return $json->where('id', $form->id)
|
||||
->where('title', $form->title)
|
||||
->whereType('properties', 'array')
|
||||
->etc();
|
||||
});
|
||||
|
||||
expect($form->views()->count())->toBe(0);
|
||||
});
|
||||
|
||||
it('can see form and count view for guest', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$this->actingAsGuest();
|
||||
|
||||
$this->getJson(route('forms.show', $form->slug))
|
||||
->assertSuccessful()
|
||||
->assertJson(function (\Illuminate\Testing\Fluent\AssertableJson $json) use ($form) {
|
||||
return $json->where('id', $form->id)
|
||||
->where('title', $form->title)
|
||||
->whereType('properties', 'array')
|
||||
->etc();
|
||||
});
|
||||
|
||||
expect($form->views()->count())->toBe(1);
|
||||
});
|
||||
35
api/tests/Feature/Forms/HideBrandingOnUpgradeTest.php
Normal file
35
api/tests/Feature/Forms/HideBrandingOnUpgradeTest.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
it('can hide branding on upgrade', function () {
|
||||
$user = $this->actingAsUser();
|
||||
// Create workspaces and forms
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
for ($j = 0; $j < 3; $j++) {
|
||||
$this->createForm($user, $workspace);
|
||||
}
|
||||
}
|
||||
|
||||
// Forms don't have branding removed when created
|
||||
$forms = $user->workspaces()->with('forms')->get()->pluck('forms')->flatten();
|
||||
$forms->each(function ($form) {
|
||||
$this->assertEquals($form->no_branding, false);
|
||||
});
|
||||
|
||||
// User subscribes
|
||||
$user->subscriptions()->create([
|
||||
'type' => 'default',
|
||||
'stripe_id' => Str::random(),
|
||||
'stripe_status' => 'active',
|
||||
'stripe_price' => Str::random(),
|
||||
'quantity' => 1,
|
||||
]);
|
||||
|
||||
// Forms have branding removed after subscription
|
||||
$forms = $user->workspaces()->with('forms')->get()->pluck('forms')->flatten();
|
||||
$forms->each(function ($form) {
|
||||
$this->assertEquals($form->no_branding, true);
|
||||
});
|
||||
});
|
||||
185
api/tests/Feature/Forms/MatrixInputTest.php
Normal file
185
api/tests/Feature/Forms/MatrixInputTest.php
Normal file
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
use Tests\Helpers\FormSubmissionDataFactory;
|
||||
|
||||
it('can submit form with valid matrix input', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$matrixProperty = [
|
||||
'id' => 'matrix_field',
|
||||
'name' => 'Matrix Question',
|
||||
'type' => 'matrix',
|
||||
'rows' => ['Row 1', 'Row 2', 'Row 3'],
|
||||
'columns' => ['Column A', 'Column B', 'Column C'],
|
||||
'required' => true
|
||||
];
|
||||
|
||||
$form->properties = array_merge($form->properties, [$matrixProperty]);
|
||||
$form->update();
|
||||
|
||||
$submissionData = [
|
||||
'matrix_field' => [
|
||||
'Row 1' => 'Column A',
|
||||
'Row 2' => 'Column B',
|
||||
'Row 3' => 'Column C'
|
||||
]
|
||||
];
|
||||
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, $submissionData);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('cannot submit form with invalid matrix input', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$matrixProperty = [
|
||||
'id' => 'matrix_field',
|
||||
'name' => 'Matrix Question',
|
||||
'type' => 'matrix',
|
||||
'rows' => ['Row 1', 'Row 2', 'Row 3'],
|
||||
'columns' => ['Column A', 'Column B', 'Column C'],
|
||||
'required' => true
|
||||
];
|
||||
|
||||
$form->properties = array_merge($form->properties, [$matrixProperty]);
|
||||
$form->update();
|
||||
|
||||
$submissionData = [
|
||||
'matrix_field' => [
|
||||
'Row 1' => 'Column A',
|
||||
'Row 2' => 'Invalid Column',
|
||||
'Row 3' => 'Column C'
|
||||
]
|
||||
];
|
||||
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, $submissionData);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertStatus(422)
|
||||
->assertJson([
|
||||
'message' => "Invalid value 'Invalid Column' for row 'Row 2'.",
|
||||
'errors' => [
|
||||
'matrix_field' => [
|
||||
"Invalid value 'Invalid Column' for row 'Row 2'."
|
||||
]
|
||||
]
|
||||
]);
|
||||
});
|
||||
|
||||
it('can submit form with optional matrix input left empty', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$matrixProperty = [
|
||||
'id' => 'matrix_field',
|
||||
'name' => 'Matrix Question',
|
||||
'type' => 'matrix',
|
||||
'rows' => ['Row 1', 'Row 2', 'Row 3'],
|
||||
'columns' => ['Column A', 'Column B', 'Column C'],
|
||||
'required' => false
|
||||
];
|
||||
|
||||
$form->properties = array_merge($form->properties, [$matrixProperty]);
|
||||
$form->update();
|
||||
|
||||
$submissionData = [
|
||||
'matrix_field' => []
|
||||
];
|
||||
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, $submissionData);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('cannot submit form with required matrix input left empty', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$matrixProperty = [
|
||||
'id' => 'matrix_field',
|
||||
'name' => 'Matrix Question',
|
||||
'type' => 'matrix',
|
||||
'rows' => ['Row 1', 'Row 2', 'Row 3'],
|
||||
'columns' => ['Column A', 'Column B', 'Column C'],
|
||||
'required' => true
|
||||
];
|
||||
|
||||
$form->properties = array_merge($form->properties, [$matrixProperty]);
|
||||
$form->update();
|
||||
|
||||
$submissionData = [
|
||||
'matrix_field' => []
|
||||
];
|
||||
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, $submissionData);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertStatus(422)
|
||||
->assertJson([
|
||||
'message' => 'The Matrix Question field is required.',
|
||||
'errors' => [
|
||||
'matrix_field' => [
|
||||
'The Matrix Question field is required.'
|
||||
]
|
||||
]
|
||||
]);
|
||||
});
|
||||
|
||||
it('can validate matrix input with precognition', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$matrixProperty = [
|
||||
'id' => 'matrix_field',
|
||||
'name' => 'Matrix Question',
|
||||
'type' => 'matrix',
|
||||
'rows' => ['Row 1', 'Row 2', 'Row 3'],
|
||||
'columns' => ['Column A', 'Column B', 'Column C'],
|
||||
'required' => true
|
||||
];
|
||||
|
||||
$form->properties = array_merge($form->properties, [$matrixProperty]);
|
||||
$form->update();
|
||||
|
||||
$submissionData = [
|
||||
'matrix_field' => [
|
||||
'Row 1' => 'Column A',
|
||||
'Row 2' => 'Invalid Column',
|
||||
'Row 3' => 'Column C'
|
||||
]
|
||||
];
|
||||
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, $submissionData);
|
||||
|
||||
$response = $this->withPrecognition()->withHeaders([
|
||||
'Precognition-Validate-Only' => 'matrix_field'
|
||||
])
|
||||
->postJson(route('forms.answer', $form->slug), $formData);
|
||||
|
||||
$response->assertStatus(422)
|
||||
->assertJson([
|
||||
'errors' => [
|
||||
'matrix_field' => [
|
||||
'Invalid value \'Invalid Column\' for row \'Row 2\'.'
|
||||
]
|
||||
]
|
||||
]);
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Tests\Helpers\FormSubmissionDataFactory;
|
||||
|
||||
it('can validate Update Workspace Select Option Job', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->createForm($user, $workspace);
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form);
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can validate scope with active subscription', function () {
|
||||
$this->createProUser();
|
||||
$this->createUser();
|
||||
$this->createProUser();
|
||||
$this->createProUser();
|
||||
$this->createUser();
|
||||
|
||||
expect(User::WithActiveSubscription()->count())->toBe(3);
|
||||
});
|
||||
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
use App\Integrations\Data\SpreadsheetData;
|
||||
use App\Integrations\Google\Google;
|
||||
use App\Integrations\Google\Sheets\SpreadsheetManager;
|
||||
use App\Models\Integration\FormIntegration;
|
||||
use App\Models\OAuthProvider;
|
||||
|
||||
use function PHPUnit\Framework\assertCount;
|
||||
use function PHPUnit\Framework\assertEquals;
|
||||
use function PHPUnit\Framework\assertSame;
|
||||
|
||||
test('build columns', function () {
|
||||
/** @var \App\Models\User $user */
|
||||
$user = $this->createUser();
|
||||
|
||||
/** @var \App\Models\Workspace $workspace */
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
|
||||
/** @var \App\Models\Forms $form */
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
/** @var \App\Models\OAuthProvider $provider */
|
||||
$provider = OAuthProvider::factory()
|
||||
->for($user)
|
||||
->create();
|
||||
|
||||
/** @var FormIntegration $integration */
|
||||
$integration = FormIntegration::factory()
|
||||
->for($form)
|
||||
->for($provider, 'provider')
|
||||
->create([
|
||||
'data' => new SpreadsheetData(
|
||||
url: 'https://google.com',
|
||||
spreadsheet_id: 'sp_test',
|
||||
columns: []
|
||||
)
|
||||
]);
|
||||
|
||||
$google = new Google($integration);
|
||||
|
||||
$manager = new SpreadsheetManager($google, $integration);
|
||||
|
||||
$columns = $manager->buildColumns();
|
||||
|
||||
assertCount(14, $columns);
|
||||
|
||||
foreach ($columns as $key => $column) {
|
||||
assertEquals($form->properties[$key]['id'], $column['id']);
|
||||
assertEquals($form->properties[$key]['name'], $column['name']);
|
||||
}
|
||||
});
|
||||
|
||||
test('update columns', function () {
|
||||
/** @var \App\Models\User $user */
|
||||
$user = $this->createUser();
|
||||
|
||||
/** @var \App\Models\Workspace $workspace */
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
|
||||
/** @var \App\Models\Forms $form */
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$form->update([
|
||||
'properties' => [
|
||||
['id' => '000', 'name' => 'First', 'type' => 'text'],
|
||||
['id' => '001', 'name' => 'Second', 'type' => 'text'],
|
||||
]
|
||||
]);
|
||||
|
||||
/** @var \App\Models\OAuthProvider $provider */
|
||||
$provider = OAuthProvider::factory()
|
||||
->for($user)
|
||||
->create();
|
||||
|
||||
/** @var FormIntegration $integration */
|
||||
$integration = FormIntegration::factory()
|
||||
->for($form)
|
||||
->for($provider, 'provider')
|
||||
->create([
|
||||
'data' => new SpreadsheetData(
|
||||
url: 'https://google.com',
|
||||
spreadsheet_id: 'sp_test',
|
||||
columns: [
|
||||
['id' => '000', 'name' => 'First', 'type' => 'text'],
|
||||
['id' => '001', 'name' => 'Second', 'type' => 'text'],
|
||||
]
|
||||
)
|
||||
]);
|
||||
|
||||
|
||||
$google = new Google($integration);
|
||||
$manager = new SpreadsheetManager($google, $integration);
|
||||
|
||||
$manager->buildColumns();
|
||||
|
||||
$form->update([
|
||||
'properties' => [
|
||||
['id' => '000', 'name' => 'First name', 'type' => 'text'],
|
||||
['id' => '002', 'name' => 'Email', 'type' => 'text'],
|
||||
]
|
||||
]);
|
||||
|
||||
$integration->refresh();
|
||||
$columns = $manager->buildColumns();
|
||||
|
||||
assertCount(3, $columns);
|
||||
assertEquals('First name', $columns[0]['name']);
|
||||
assertEquals('Second', $columns[1]['name']);
|
||||
assertEquals('Email', $columns[2]['name']);
|
||||
});
|
||||
|
||||
test('build row', function () {
|
||||
/** @var \App\Models\User $user */
|
||||
$user = $this->createUser();
|
||||
|
||||
/** @var \App\Models\Workspace $workspace */
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
|
||||
/** @var \App\Models\Forms $form */
|
||||
$form = $this->createForm($user, $workspace);
|
||||
|
||||
$form->update([
|
||||
'properties' => [
|
||||
['id' => '000', 'name' => 'First', 'type' => 'text'],
|
||||
['id' => '001', 'name' => 'Second', 'type' => 'text'],
|
||||
['id' => '002', 'name' => 'Third', 'type' => 'text'],
|
||||
]
|
||||
]);
|
||||
|
||||
/** @var \App\Models\OAuthProvider $provider */
|
||||
$provider = OAuthProvider::factory()
|
||||
->for($user)
|
||||
->create();
|
||||
|
||||
/** @var FormIntegration $integration */
|
||||
$integration = FormIntegration::factory()
|
||||
->for($form)
|
||||
->for($provider, 'provider')
|
||||
->create([
|
||||
'data' => new SpreadsheetData(
|
||||
url: 'https://google.com',
|
||||
spreadsheet_id: 'sp_test',
|
||||
columns: [
|
||||
['id' => '000', 'name' => 'First'],
|
||||
['id' => '001', 'name' => 'Second'],
|
||||
['id' => '002', 'name' => 'Third'],
|
||||
]
|
||||
)
|
||||
]);
|
||||
|
||||
|
||||
$google = new Google($integration);
|
||||
$manager = new SpreadsheetManager($google, $integration);
|
||||
|
||||
$submission = [
|
||||
'002' => 'Third value',
|
||||
'000' => 'First value',
|
||||
];
|
||||
|
||||
$row = $manager->buildRow($submission);
|
||||
|
||||
assertSame(['First value', '', 'Third value'], $row);
|
||||
});
|
||||
37
api/tests/Feature/LoginTest.php
Normal file
37
api/tests/Feature/LoginTest.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
it('can login to Forms', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->postJson('/login', [
|
||||
'email' => $user->email,
|
||||
'password' => 'password',
|
||||
])
|
||||
->assertSuccessful()
|
||||
->assertJsonStructure(['token', 'expires_in'])
|
||||
->assertJson(['token_type' => 'bearer']);
|
||||
});
|
||||
|
||||
it('can fetch current user', function () {
|
||||
$this->actingAs(User::factory()->create())
|
||||
->getJson('/user')
|
||||
->assertSuccessful()
|
||||
->assertJsonStructure(['id', 'name', 'email']);
|
||||
});
|
||||
|
||||
it('can log out', function () {
|
||||
$this->postJson('/login', [
|
||||
'email' => User::factory()->create()->email,
|
||||
'password' => 'password',
|
||||
])->assertSuccessful();
|
||||
|
||||
$this->assertAuthenticated();
|
||||
$this->postJson('/logout')
|
||||
->assertSuccessful();
|
||||
|
||||
$this->assertGuest();
|
||||
$this->getJson('/user')
|
||||
->assertStatus(401);
|
||||
});
|
||||
62
api/tests/Feature/RegisterTest.php
Normal file
62
api/tests/Feature/RegisterTest.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
it('can register', function () {
|
||||
$this->postJson('/register', [
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@test.app',
|
||||
'hear_about_us' => 'google',
|
||||
'password' => 'secret',
|
||||
'password_confirmation' => 'secret',
|
||||
'agree_terms' => true,
|
||||
])
|
||||
->assertSuccessful()
|
||||
->assertJsonStructure(['id', 'name', 'email']);
|
||||
$this->assertDatabaseHas('users', [
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@test.app',
|
||||
]);
|
||||
});
|
||||
|
||||
it('cannot register with existing email', function () {
|
||||
User::factory()->create(['email' => 'test@test.app']);
|
||||
|
||||
$this->postJson('/register', [
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@test.app',
|
||||
'password' => 'secret',
|
||||
'password_confirmation' => 'secret',
|
||||
])
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors(['email']);
|
||||
});
|
||||
|
||||
it('cannot register with disposable email', function () {
|
||||
// Select random email
|
||||
$email = [
|
||||
'dumliyupse@gufum.com',
|
||||
'kcs79722@zslsz.com',
|
||||
'pfizexwxtdifxupdhr@tpwlb.com',
|
||||
'qvj86ypqfm@email.edu.pl',
|
||||
][rand(0, 3)];
|
||||
|
||||
$this->postJson('/register', [
|
||||
'name' => 'Test disposable',
|
||||
'email' => $email,
|
||||
'hear_about_us' => 'google',
|
||||
'password' => 'secret',
|
||||
'password_confirmation' => 'secret',
|
||||
'agree_terms' => true,
|
||||
])
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors(['email'])
|
||||
->assertJson([
|
||||
'message' => 'Disposable email addresses are not allowed.',
|
||||
'errors' => [
|
||||
'email' => [
|
||||
'Disposable email addresses are not allowed.',
|
||||
],
|
||||
],
|
||||
]);
|
||||
});
|
||||
31
api/tests/Feature/SettingsTest.php
Normal file
31
api/tests/Feature/SettingsTest.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
it('update profile info', function () {
|
||||
$this->actingAs($user = User::factory()->create())
|
||||
->patchJson('/settings/profile', [
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@test.app',
|
||||
])
|
||||
->assertSuccessful()
|
||||
->assertJsonStructure(['id', 'name', 'email']);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@test.app',
|
||||
]);
|
||||
});
|
||||
|
||||
it('update password', function () {
|
||||
$this->actingAs($user = User::factory()->create())
|
||||
->patchJson('/settings/password', [
|
||||
'password' => 'updated',
|
||||
'password_confirmation' => 'updated',
|
||||
])
|
||||
->assertSuccessful();
|
||||
|
||||
$this->assertTrue(Hash::check('updated', $user->password));
|
||||
});
|
||||
59
api/tests/Feature/Submissions/EditSubmissionTest.php
Normal file
59
api/tests/Feature/Submissions/EditSubmissionTest.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
use Tests\Helpers\FormSubmissionDataFactory;
|
||||
|
||||
it('can update form submission', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->makeForm($user, $workspace);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'closes_at' => \Carbon\Carbon::now()->addDays(1)->toDateTimeString(),
|
||||
]);
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, ['text' => 'John']);
|
||||
$textFieldId = array_keys($formData)[0];
|
||||
$updatedFormData = $formData;
|
||||
$updatedFormTextValue = 'Updated text';
|
||||
$updatedFormData[$textFieldId] = $updatedFormTextValue;
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
$submission = $form->submissions()->first();
|
||||
$updateResponse = $this->putJson(route('open.forms.submissions.update', ['id' => $form->id, 'submission_id' => $submission->id]), $updatedFormData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Record successfully updated.',
|
||||
]);
|
||||
$expectedTextString = $updateResponse->json('data')['data'][$textFieldId];
|
||||
expect($expectedTextString)->toBe($updatedFormTextValue);
|
||||
$updatedSubmission = $form->submissions()->first();
|
||||
expect($updatedSubmission->data[$textFieldId])->toBe($updatedFormTextValue);
|
||||
});
|
||||
|
||||
it('cannot update form submission as non admin', function () {
|
||||
$secondUser = $this->createUser();
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->makeForm($user, $workspace);
|
||||
$form = $this->createForm($user, $workspace, [
|
||||
'closes_at' => \Carbon\Carbon::now()->addDays(1)->toDateTimeString(),
|
||||
]);
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form, ['text' => 'John']);
|
||||
$textFieldId = array_keys($formData)[0];
|
||||
$updatedFormData = $formData;
|
||||
$updatedFormTextValue = 'Updated text';
|
||||
$updatedFormData[$textFieldId] = $updatedFormTextValue;
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
$submission = $form->submissions()->first();
|
||||
$this->actingAs($secondUser);
|
||||
$updateResponse = $this->putJson(route('open.forms.submissions.update', ['id' => $form->id, 'submission_id' => $submission->id]), $updatedFormData)
|
||||
->assertStatus(403);
|
||||
});
|
||||
30
api/tests/Feature/TemplateTest.php
Normal file
30
api/tests/Feature/TemplateTest.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
it('can create template', function () {
|
||||
$user = $this->createUser([
|
||||
'email' => 'admin@opnform.com',
|
||||
]);
|
||||
$this->actingAsUser($user);
|
||||
|
||||
// Create Form
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->makeForm($user, $workspace);
|
||||
|
||||
// Create Template
|
||||
$templateData = [
|
||||
'name' => 'Demo Template',
|
||||
'slug' => 'demo_template',
|
||||
'short_description' => 'Short description here...',
|
||||
'description' => 'Some long description here...',
|
||||
'image_url' => 'https://d3ietpyl4f2d18.cloudfront.net/6c35a864-ee3a-4039-80a4-040b6c20ac60/img/pages/welcome/product_cover.jpg',
|
||||
'publicly_listed' => true,
|
||||
'form' => $form->getAttributes(),
|
||||
'questions' => [['question' => 'Question 1', 'answer' => 'Answer 1 will be here...']],
|
||||
];
|
||||
$this->postJson(route('templates.create', $templateData))
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Template was created.',
|
||||
]);
|
||||
});
|
||||
150
api/tests/Feature/UserInviteTest.php
Normal file
150
api/tests/Feature/UserInviteTest.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
use App\Models\UserInvite;
|
||||
use Carbon\Carbon;
|
||||
|
||||
it('can register with invite token', function () {
|
||||
$this->withoutExceptionHandling();
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$email = 'invitee@gmail.com';
|
||||
$inviteData = ['email' => $email, 'role' => 'user'];
|
||||
$this->postJson(route('open.workspaces.users.add', $workspace->id), $inviteData)
|
||||
->assertSuccessful();
|
||||
|
||||
expect($workspace->invites()->count())->toBe(1);
|
||||
$userInvite = UserInvite::latest()->first();
|
||||
$token = $userInvite->token;
|
||||
|
||||
$this->postJson('/logout')
|
||||
->assertSuccessful();
|
||||
|
||||
// Register with token
|
||||
$response = $this->postJson('/register', [
|
||||
'name' => 'Invitee',
|
||||
'email' => $email,
|
||||
'hear_about_us' => 'google',
|
||||
'password' => 'secret',
|
||||
'password_confirmation' => 'secret',
|
||||
'agree_terms' => true,
|
||||
'invite_token' => $token,
|
||||
]);
|
||||
$response->assertSuccessful();
|
||||
expect($workspace->users()->count())->toBe(2);
|
||||
});
|
||||
|
||||
it('cannot register with expired invite token', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$email = 'invitee@gmail.com';
|
||||
$inviteData = ['email' => $email, 'role' => 'user'];
|
||||
$this->postJson(route('open.workspaces.users.add', $workspace->id), $inviteData)
|
||||
->assertSuccessful();
|
||||
|
||||
expect($workspace->invites()->count())->toBe(1);
|
||||
$userInvite = UserInvite::latest()->first();
|
||||
$token = $userInvite->token;
|
||||
|
||||
$this->postJson('/logout')
|
||||
->assertSuccessful();
|
||||
|
||||
Carbon::setTestNow(now()->addDays(8));
|
||||
// Register with token
|
||||
$response = $this->postJson('/register', [
|
||||
'name' => 'Invitee',
|
||||
'email' => $email,
|
||||
'hear_about_us' => 'google',
|
||||
'password' => 'secret',
|
||||
'password_confirmation' => 'secret',
|
||||
'agree_terms' => true,
|
||||
'invite_token' => $token,
|
||||
]);
|
||||
$response->assertStatus(400)->assertJson([
|
||||
'message' => 'Invite token has expired.',
|
||||
]);
|
||||
expect($workspace->users()->count())->toBe(1);
|
||||
});
|
||||
|
||||
it('cannot re-register with accepted invite token', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$email = 'invitee@gmail.com';
|
||||
$inviteData = ['email' => $email, 'role' => 'user'];
|
||||
$this->postJson(route('open.workspaces.users.add', $workspace->id), $inviteData)
|
||||
->assertSuccessful();
|
||||
|
||||
expect($workspace->invites()->count())->toBe(1);
|
||||
$userInvite = UserInvite::latest()->first();
|
||||
$token = $userInvite->token;
|
||||
|
||||
$this->postJson('/logout')
|
||||
->assertSuccessful();
|
||||
|
||||
// Register with token
|
||||
$response = $this->postJson('/register', [
|
||||
'name' => 'Invitee',
|
||||
'email' => $email,
|
||||
'hear_about_us' => 'google',
|
||||
'password' => 'secret',
|
||||
'password_confirmation' => 'secret',
|
||||
'agree_terms' => true,
|
||||
'invite_token' => $token,
|
||||
]);
|
||||
$response->assertSuccessful();
|
||||
expect($workspace->users()->count())->toBe(2);
|
||||
|
||||
$this->postJson('/logout')
|
||||
->assertSuccessful();
|
||||
|
||||
// Register again with same used token
|
||||
$response = $this->postJson('/register', [
|
||||
'name' => 'Invitee',
|
||||
'email' => $email,
|
||||
'hear_about_us' => 'google',
|
||||
'password' => 'secret',
|
||||
'password_confirmation' => 'secret',
|
||||
'agree_terms' => true,
|
||||
'invite_token' => $token,
|
||||
]);
|
||||
|
||||
$response->assertStatus(422)->assertJson([
|
||||
'message' => 'The email has already been taken.',
|
||||
]);
|
||||
expect($workspace->users()->count())->toBe(2);
|
||||
});
|
||||
|
||||
it('can cancel user invite', function () {
|
||||
$user = $this->actingAsUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$email = 'invitee@gmail.com';
|
||||
$inviteData = ['email' => $email, 'role' => 'user'];
|
||||
$response = $this->postJson(route('open.workspaces.users.add', $workspace->id), $inviteData)
|
||||
->assertSuccessful();
|
||||
|
||||
expect($workspace->invites()->count())->toBe(1);
|
||||
$userInvite = UserInvite::latest()->first();
|
||||
$token = $userInvite->token;
|
||||
|
||||
// Cancel the invite
|
||||
$this->deleteJson(route('open.workspaces.invites.cancel', ['workspaceId' => $workspace->id, 'inviteId' => $userInvite->id]))
|
||||
->assertSuccessful();
|
||||
|
||||
$this->postJson('/logout')
|
||||
->assertSuccessful();
|
||||
|
||||
// Register with token
|
||||
$response = $this->postJson('/register', [
|
||||
'name' => 'Invitee',
|
||||
'email' => $email,
|
||||
'hear_about_us' => 'google',
|
||||
'password' => 'secret',
|
||||
'password_confirmation' => 'secret',
|
||||
'agree_terms' => true,
|
||||
'invite_token' => $token,
|
||||
]);
|
||||
$response->assertStatus(400)->assertJson([
|
||||
'message' => 'Invite token is invalid.',
|
||||
]);
|
||||
|
||||
expect($workspace->users()->count())->toBe(1);
|
||||
});
|
||||
21
api/tests/Feature/VerificationTest.php
Normal file
21
api/tests/Feature/VerificationTest.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Events\Verified;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
it('can verify email', function () {
|
||||
$user = User::factory()->create(['email_verified_at' => null]);
|
||||
$url = URL::temporarySignedRoute('verification.verify', now()->addMinutes(60), ['user' => $user->id]);
|
||||
|
||||
Event::fake();
|
||||
|
||||
$this->postJson($url)
|
||||
->assertSuccessful()
|
||||
->assertJsonFragment(['status' => 'Your email has been verified!']);
|
||||
|
||||
Event::assertDispatched(Verified::class, function (Verified $e) use ($user) {
|
||||
return $e->user->is($user);
|
||||
});
|
||||
});
|
||||
36
api/tests/Feature/WorkspaceTest.php
Normal file
36
api/tests/Feature/WorkspaceTest.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
it('can create and delete Workspace', function () {
|
||||
$user = $this->actingAsUser();
|
||||
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
$this->postJson(route('open.workspaces.create'), [
|
||||
'name' => 'Workspace Test - '.$i,
|
||||
'icon' => '🧪',
|
||||
])
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Workspace created.',
|
||||
]);
|
||||
}
|
||||
|
||||
expect($user->workspaces()->count())->toBe(3);
|
||||
|
||||
$i = 0;
|
||||
foreach ($user->workspaces as $workspace) {
|
||||
$i++;
|
||||
if ($i !== 3) {
|
||||
$this->deleteJson(route('open.workspaces.delete', $workspace->id))
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Workspace deleted.',
|
||||
]);
|
||||
} else {
|
||||
// Last workspace can not delete
|
||||
$this->deleteJson(route('open.workspaces.delete', $workspace->id))
|
||||
->assertStatus(403);
|
||||
}
|
||||
}
|
||||
});
|
||||
90
api/tests/Feature/WorkspaceUserTest.php
Normal file
90
api/tests/Feature/WorkspaceUserTest.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Workspace;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use App\Mail\UserInvitationEmail;
|
||||
|
||||
beforeEach(function () {
|
||||
$this->user = $this->actingAsProUser();
|
||||
$this->workspace = Workspace::factory()->create();
|
||||
$this->workspace->users()->attach($this->user, ['role' => 'admin']);
|
||||
});
|
||||
|
||||
it('can list users in a workspace', function () {
|
||||
|
||||
$this->getJson(route('open.workspaces.users.index', ['workspaceId' => $this->workspace->id]))
|
||||
->assertSuccessful()
|
||||
->assertJsonCount(1);
|
||||
});
|
||||
|
||||
it('can add a user to a workspace', function () {
|
||||
$newUser = User::factory()->create(['email' => 'newuser@example.com']);
|
||||
$this->postJson(route('open.workspaces.users.add', ['workspaceId' => $this->workspace->id]), [
|
||||
'email' => $newUser->email,
|
||||
'role' => 'user',
|
||||
])
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'message' => 'User has been successfully added to workspace.'
|
||||
]);
|
||||
|
||||
expect($this->workspace->users()->count())->toBe(2);
|
||||
});
|
||||
|
||||
it('can send an invitation email to a non-existing user', function () {
|
||||
Mail::fake();
|
||||
|
||||
$this->postJson(route('open.workspaces.users.add', ['workspaceId' => $this->workspace->id]), [
|
||||
'email' => 'nonexisting@example.com',
|
||||
'role' => 'user',
|
||||
])
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'message' => 'Registration invitation email sent to user.'
|
||||
]);
|
||||
|
||||
Mail::assertQueued(UserInvitationEmail::class);
|
||||
});
|
||||
|
||||
it('can update user role in a workspace', function () {
|
||||
$existingUser = User::factory()->create();
|
||||
$this->workspace->users()->attach($existingUser, ['role' => 'user']);
|
||||
|
||||
$this->putJson(route('open.workspaces.users.update-role', [
|
||||
'workspaceId' => $this->workspace->id,
|
||||
'userId' => $existingUser->id
|
||||
]), [
|
||||
'role' => 'admin',
|
||||
])
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'message' => 'User role changed successfully.'
|
||||
]);
|
||||
});
|
||||
|
||||
it('can remove a user from a workspace', function () {
|
||||
$existingUser = User::factory()->create();
|
||||
$this->workspace->users()->attach($existingUser);
|
||||
|
||||
$this->deleteJson(route('open.workspaces.users.remove', [
|
||||
'workspaceId' => $this->workspace->id,
|
||||
'userId' => $existingUser->id
|
||||
]))
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'message' => 'User removed from workspace successfully.'
|
||||
]);
|
||||
|
||||
expect($this->workspace->users()->count())->toBe(1);
|
||||
});
|
||||
|
||||
it('can leave a workspace', function () {
|
||||
$this->postJson(route('open.workspaces.leave', ['workspaceId' => $this->workspace->id]))
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'message' => 'You have left the workspace successfully.'
|
||||
]);
|
||||
|
||||
expect($this->workspace->users()->count())->toBe(0);
|
||||
});
|
||||
244
api/tests/Feature/Zapier/IntegrationsTest.php
Normal file
244
api/tests/Feature/Zapier/IntegrationsTest.php
Normal file
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Integration\FormIntegration;
|
||||
use App\Models\User;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\Helpers\FormSubmissionDataFactory;
|
||||
|
||||
use function Pest\Laravel\assertDatabaseCount;
|
||||
use function Pest\Laravel\delete;
|
||||
use function Pest\Laravel\post;
|
||||
use function PHPUnit\Framework\assertEquals;
|
||||
|
||||
test('create an integration', function () {
|
||||
$user = User::factory()->create();
|
||||
$workspace = createUserWorkspace($user);
|
||||
|
||||
$form = createForm($user, $workspace, ['title' => 'First form']);
|
||||
|
||||
Sanctum::actingAs(
|
||||
$user,
|
||||
['manage-integrations']
|
||||
);
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
post(route('zapier.webhooks.store'), [
|
||||
'form_id' => $form->id,
|
||||
'hookUrl' => $hookUrl = 'https://zapier.com/hook/test'
|
||||
])
|
||||
->assertOk();
|
||||
|
||||
assertDatabaseCount('form_integrations', 1);
|
||||
|
||||
$integration = FormIntegration::first();
|
||||
|
||||
assertEquals($form->id, $integration->form_id);
|
||||
assertEquals($hookUrl, $integration->data->hook_url);
|
||||
});
|
||||
|
||||
test('cannot create an integration without a corresponding ability', function () {
|
||||
$user = User::factory()->create();
|
||||
$workspace = createUserWorkspace($user);
|
||||
|
||||
$form = createForm($user, $workspace, ['title' => 'First form']);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
post(route('zapier.webhooks.store'), [
|
||||
'form_id' => $form->id,
|
||||
'hookUrl' => 'https://zapier.com/hook/test'
|
||||
])
|
||||
->assertForbidden();
|
||||
|
||||
assertDatabaseCount('form_integrations', 0);
|
||||
});
|
||||
|
||||
test('cannot create an integration for other users form', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$user2 = User::factory()->create();
|
||||
$workspace = createUserWorkspace($user2);
|
||||
|
||||
$form = createForm($user2, $workspace, ['title' => 'First form']);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
post(route('zapier.webhooks.store'), [
|
||||
'form_id' => $form->id,
|
||||
'hookUrl' => 'https://zapier.com/hook/test'
|
||||
])
|
||||
->assertForbidden();
|
||||
|
||||
assertDatabaseCount('form_integrations', 0);
|
||||
});
|
||||
|
||||
test('delete an integration', function () {
|
||||
$user = User::factory()->create();
|
||||
$workspace = createUserWorkspace($user);
|
||||
|
||||
$form = createForm($user, $workspace, ['title' => 'First form']);
|
||||
|
||||
Sanctum::actingAs(
|
||||
$user,
|
||||
['manage-integrations']
|
||||
);
|
||||
|
||||
$integration = FormIntegration::factory()
|
||||
->for($form)
|
||||
->create([
|
||||
'data' => [
|
||||
'hook_url' => $hookUrl = 'https://zapier.com/hook/test'
|
||||
]
|
||||
]);
|
||||
|
||||
assertDatabaseCount('form_integrations', 1);
|
||||
|
||||
delete(route('zapier.webhooks.destroy', $integration), [
|
||||
'form_id' => $form->id,
|
||||
'hookUrl' => $hookUrl,
|
||||
])
|
||||
->assertOk();
|
||||
|
||||
assertDatabaseCount('form_integrations', 0);
|
||||
});
|
||||
|
||||
test('cannot delete an integration with an incorrect hook url', function () {
|
||||
$user = User::factory()->create();
|
||||
$workspace = createUserWorkspace($user);
|
||||
|
||||
$form = createForm($user, $workspace, ['title' => 'First form']);
|
||||
|
||||
Sanctum::actingAs(
|
||||
$user,
|
||||
['manage-integrations']
|
||||
);
|
||||
|
||||
$integration = FormIntegration::factory()
|
||||
->for($form)
|
||||
->create([
|
||||
'data' => [
|
||||
'hook_url' => 'https://zapier.com/hook/test'
|
||||
]
|
||||
]);
|
||||
|
||||
delete(route('zapier.webhooks.destroy', $integration), [
|
||||
'form_id' => $form->id,
|
||||
'hookUrl' => 'https://google.com',
|
||||
])
|
||||
->assertOk();
|
||||
|
||||
assertDatabaseCount('form_integrations', 1);
|
||||
});
|
||||
|
||||
test('poll for the latest submission', function () {
|
||||
$user = User::factory()->create();
|
||||
$workspace = createUserWorkspace($user);
|
||||
$form = createForm($user, $workspace, [
|
||||
'properties' => [
|
||||
[
|
||||
'id' => 'title',
|
||||
'name' => 'Name',
|
||||
'type' => 'text',
|
||||
'hidden' => false,
|
||||
'required' => true,
|
||||
'logic' => [
|
||||
'conditions' => null,
|
||||
'actions' => [],
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => 'age',
|
||||
'name' => 'Age',
|
||||
'type' => 'number',
|
||||
'hidden' => false,
|
||||
'required' => true,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
// Create a submission for the form
|
||||
$formData = FormSubmissionDataFactory::generateSubmissionData($form);
|
||||
|
||||
$this->postJson(route('forms.answer', $form->slug), $formData)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form submission saved.',
|
||||
]);
|
||||
|
||||
// Create a webhook integration for the form
|
||||
$integration = FormIntegration::factory()
|
||||
->for($form)
|
||||
->create([
|
||||
'data' => [
|
||||
'hook_url' => 'https://zapier.com/hook/test'
|
||||
]
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($user, ['view', 'manage-integrations']);
|
||||
|
||||
// Call the poll endpoint
|
||||
$response = $this->getJson(route('zapier.webhooks.poll', ['form_id' => $form->id]));
|
||||
|
||||
// Assert the response status is OK
|
||||
$response->assertOk();
|
||||
|
||||
// Decode the response data
|
||||
$responseData = $response->json()[0];
|
||||
$receivedData = collect($responseData['data'])->values()->pluck('value')->toArray();
|
||||
|
||||
$this->assertEmpty(array_diff(array_values($formData), $receivedData));
|
||||
});
|
||||
|
||||
test('make up a submission when polling without any submission', function () {
|
||||
$user = User::factory()->create();
|
||||
$workspace = createUserWorkspace($user);
|
||||
$form = createForm($user, $workspace, [
|
||||
'properties' => [
|
||||
[
|
||||
'id' => 'title',
|
||||
'name' => 'Name',
|
||||
'type' => 'text',
|
||||
'hidden' => false,
|
||||
'required' => true,
|
||||
'logic' => [
|
||||
'conditions' => null,
|
||||
'actions' => [],
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => 'age',
|
||||
'name' => 'Age',
|
||||
'type' => 'number',
|
||||
'hidden' => false,
|
||||
'required' => true,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
// Create a webhook integration for the form
|
||||
$integration = FormIntegration::factory()
|
||||
->for($form)
|
||||
->create([
|
||||
'data' => [
|
||||
'hook_url' => 'https://zapier.com/hook/test'
|
||||
]
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($user, ['view', 'manage-integrations']);
|
||||
|
||||
// Call the poll endpoint
|
||||
$this->withoutExceptionHandling();
|
||||
$response = $this->getJson(route('zapier.webhooks.poll', ['form_id' => $form->id]));
|
||||
// Assert the response status is OK
|
||||
$response->assertOk();
|
||||
|
||||
// Decode the response data
|
||||
$responseData = $response->json()[0];
|
||||
|
||||
ray($responseData);
|
||||
|
||||
ray($responseData);
|
||||
$this->assertNotEmpty($responseData['data']);
|
||||
$this->assertTrue(count($responseData['data']) == 2);
|
||||
});
|
||||
61
api/tests/Feature/Zapier/ListFormsTest.php
Normal file
61
api/tests/Feature/Zapier/ListFormsTest.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
|
||||
use function Pest\Laravel\get;
|
||||
|
||||
test('list all forms of a given workspace', function () {
|
||||
$user = User::factory()->create();
|
||||
$workspace = createUserWorkspace($user);
|
||||
|
||||
$form1 = createForm($user, $workspace, ['title' => 'First form']);
|
||||
$form2 = createForm($user, $workspace, ['title' => 'Second form']);
|
||||
|
||||
Sanctum::actingAs(
|
||||
$user,
|
||||
['list-forms']
|
||||
);
|
||||
|
||||
get(route('zapier.forms', ['workspace_id' => $workspace->id]))
|
||||
->assertOk()
|
||||
->assertJsonCount(2)
|
||||
->assertJson([
|
||||
[
|
||||
'id' => $form1->id,
|
||||
'name' => $form1->title,
|
||||
],
|
||||
[
|
||||
'id' => $form2->id,
|
||||
'name' => $form2->title,
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
test('cannot list forms without a corresponding ability', function () {
|
||||
$user = User::factory()->create();
|
||||
$workspace = createUserWorkspace($user);
|
||||
|
||||
$form1 = createForm($user, $workspace, ['title' => 'First form']);
|
||||
$form2 = createForm($user, $workspace, ['title' => 'Second form']);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
get(route('zapier.forms', ['workspace_id' => $workspace->id]))
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
test('cannot other users forms', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$user2 = User::factory()->create();
|
||||
$workspace = createUserWorkspace($user2);
|
||||
|
||||
$form1 = createForm($user, $workspace, ['title' => 'First form']);
|
||||
$form2 = createForm($user, $workspace, ['title' => 'Second form']);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
get(route('zapier.forms', ['workspace_id' => $workspace->id]))
|
||||
->assertForbidden();
|
||||
});
|
||||
39
api/tests/Feature/Zapier/ListWorkspacesTest.php
Normal file
39
api/tests/Feature/Zapier/ListWorkspacesTest.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
|
||||
use function Pest\Laravel\get;
|
||||
|
||||
test('list all workspaces of a user', function () {
|
||||
$user = User::factory()->create();
|
||||
$workspace = createUserWorkspace($user);
|
||||
|
||||
$anotherUser = User::factory()->create();
|
||||
$anotherWorkspace = createUserWorkspace($anotherUser);
|
||||
|
||||
Sanctum::actingAs(
|
||||
$user,
|
||||
['list-workspaces']
|
||||
);
|
||||
|
||||
get(route('zapier.workspaces'))
|
||||
->assertOk()
|
||||
->assertJsonCount(1)
|
||||
->assertJson([
|
||||
[
|
||||
'id' => $workspace->id,
|
||||
'name' => $workspace->name,
|
||||
]
|
||||
]);
|
||||
});
|
||||
|
||||
test('cannot list workspaces without a corresponding ability', function () {
|
||||
$user = User::factory()->create();
|
||||
$workspace = createUserWorkspace($user);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
get(route('zapier.workspaces'))
|
||||
->assertForbidden();
|
||||
});
|
||||
24
api/tests/Feature/Zapier/ValidateAuthTest.php
Normal file
24
api/tests/Feature/Zapier/ValidateAuthTest.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
|
||||
use function Pest\Laravel\get;
|
||||
|
||||
test('validate auth', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
get(route('zapier.validate'))
|
||||
->assertOk()
|
||||
->assertJson([
|
||||
'name' => $user->name,
|
||||
'email' => $user->email,
|
||||
]);
|
||||
});
|
||||
|
||||
test('cannot validate auth with incorrect credentials', function () {
|
||||
get(route('zapier.validate'))
|
||||
->assertUnauthorized();
|
||||
});
|
||||
126
api/tests/Helpers/FormSubmissionDataFactory.php
Normal file
126
api/tests/Helpers/FormSubmissionDataFactory.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Helpers;
|
||||
|
||||
use App\Models\Forms\Form;
|
||||
use Faker;
|
||||
|
||||
class FormSubmissionDataFactory
|
||||
{
|
||||
private ?Faker\Generator $faker;
|
||||
|
||||
/**
|
||||
* If true, then format expected by answer endpoint
|
||||
* otherwise, format of answer as we store it in the FormSubmission's data
|
||||
*/
|
||||
private bool $answerFormat = true;
|
||||
|
||||
public function __construct(private Form $form)
|
||||
{
|
||||
$this->faker = Faker\Factory::create();
|
||||
}
|
||||
|
||||
public static function generateSubmissionData(Form $form, array $data = [])
|
||||
{
|
||||
return (new self($form))->createSubmissionData($data);
|
||||
}
|
||||
|
||||
public function asFormSubmissionData()
|
||||
{
|
||||
$this->answerFormat = false;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function createSubmissionData($mergeData = [])
|
||||
{
|
||||
$data = [];
|
||||
|
||||
// for all non-hidden fields in form, create some fake data
|
||||
collect($this->form->properties)->each(function ($property) use (&$data) {
|
||||
$value = null;
|
||||
switch ($property['type']) {
|
||||
case 'text':
|
||||
$value = $this->faker->name();
|
||||
break;
|
||||
case 'email':
|
||||
$value = $this->faker->unique()->email();
|
||||
break;
|
||||
case 'checkbox':
|
||||
$value = $this->faker->randomElement([true, false]);
|
||||
break;
|
||||
case 'number':
|
||||
$value = $this->faker->numberBetween();
|
||||
break;
|
||||
case 'rating':
|
||||
case 'scale':
|
||||
$value = $this->faker->numberBetween(1, 5);
|
||||
break;
|
||||
case 'slider':
|
||||
$value = $this->faker->numberBetween(0, 50);
|
||||
break;
|
||||
case 'url':
|
||||
$value = $this->faker->url();
|
||||
break;
|
||||
case 'phone_number':
|
||||
$value = 'FR+33749119783';
|
||||
break;
|
||||
case 'date':
|
||||
$value = $this->faker->date();
|
||||
break;
|
||||
case 'select':
|
||||
$value = $this->generateSelectValue($property);
|
||||
break;
|
||||
case 'multi_select':
|
||||
$value = $this->generateMultiSelectValues($property);
|
||||
break;
|
||||
case 'files':
|
||||
$value = null; // TODO: Will do this in future
|
||||
break;
|
||||
}
|
||||
$data[$property['id']] = $value;
|
||||
});
|
||||
|
||||
if (!$this->answerFormat) {
|
||||
$data = $this->formatAsSubmissionData($data);
|
||||
}
|
||||
|
||||
return array_merge($data, $mergeData);
|
||||
}
|
||||
|
||||
private function formatAsSubmissionData($data)
|
||||
{
|
||||
collect($this->form->properties)->each(function ($property) use (&$data) {
|
||||
if ($property['type'] === 'phone_number') {
|
||||
$data[$property['id']] = '+33749119783';
|
||||
}
|
||||
});
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function generateSelectValue($property)
|
||||
{
|
||||
$values = [];
|
||||
if (isset($property['select']['options']) && count($property['select']['options']) > 0) {
|
||||
$values = collect($property['select']['options'])->map(function ($option) {
|
||||
return $option['name'];
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
return ($values) ? $this->faker->randomElement($values) : null;
|
||||
}
|
||||
|
||||
private function generateMultiSelectValues($property)
|
||||
{
|
||||
$values = [];
|
||||
if (isset($property['multi_select']['options']) && count($property['multi_select']['options']) > 0) {
|
||||
$values = collect($property['multi_select']['options'])->map(function ($option) {
|
||||
return $option['name'];
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
return ($values) ? $this->faker->randomElements(
|
||||
$values,
|
||||
$this->faker->numberBetween(1, count($values))
|
||||
) : null;
|
||||
}
|
||||
}
|
||||
54
api/tests/Pest.php
Normal file
54
api/tests/Pest.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Test Case
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The closure you provide to your test functions is always bound to a specific PHPUnit test
|
||||
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
|
||||
| need to change it using the "uses()" function to bind a different classes or traits.
|
||||
|
|
||||
*/
|
||||
|
||||
use App\Models\Forms\Form;
|
||||
use App\Models\User;
|
||||
use App\Models\Workspace;
|
||||
|
||||
uses(\Tests\TestCase::class)->in('Feature');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Expectations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When you're writing tests, you often need to check that values meet certain conditions. The
|
||||
| "expect()" function gives you access to a set of "expectations" methods that you can use
|
||||
| to assert different things. Of course, you may extend the Expectation API at any time.
|
||||
|
|
||||
*/
|
||||
|
||||
expect()->extend('toBeOne', function () {
|
||||
return $this->toBe(1);
|
||||
});
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Functions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
|
||||
| project that you don't want to repeat in every file. Here you can also expose helpers as
|
||||
| global functions to help you to reduce the number of lines of code in your test files.
|
||||
|
|
||||
*/
|
||||
|
||||
function createUserWorkspace(User $user): Workspace
|
||||
{
|
||||
return test()->createUserWorkspace($user);
|
||||
}
|
||||
|
||||
function createForm(User $user, Workspace $workspace, array $data = []): Form
|
||||
{
|
||||
return test()->createForm($user, $workspace, $data);
|
||||
}
|
||||
13
api/tests/TestCase.php
Normal file
13
api/tests/TestCase.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||
|
||||
abstract class TestCase extends BaseTestCase
|
||||
{
|
||||
use CreatesApplication;
|
||||
use RefreshDatabase;
|
||||
use TestHelpers;
|
||||
}
|
||||
260
api/tests/TestHelpers.php
Normal file
260
api/tests/TestHelpers.php
Normal file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use App\Models\Forms\Form;
|
||||
use App\Models\User;
|
||||
use App\Models\Workspace;
|
||||
use Database\Factories\FormFactory;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait TestHelpers
|
||||
{
|
||||
/**
|
||||
* Creates a workspace for a user
|
||||
*/
|
||||
public function createUserWorkspace(User $user)
|
||||
{
|
||||
if (!$user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$workspace = Workspace::create([
|
||||
'name' => 'Form Testing',
|
||||
'icon' => '🧪',
|
||||
]);
|
||||
|
||||
$user->workspaces()->sync([
|
||||
$workspace->id => [
|
||||
'role' => 'admin',
|
||||
],
|
||||
], false);
|
||||
|
||||
return $workspace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Form instance (not saved)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function makeForm(User $user, Workspace $workspace, array $data = [])
|
||||
{
|
||||
$dbProperties = [
|
||||
[
|
||||
'name' => 'Name',
|
||||
'type' => 'text',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
],
|
||||
[
|
||||
'name' => 'Message',
|
||||
'type' => 'text',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
'multi_lines' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'Number',
|
||||
'type' => 'number',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
],
|
||||
[
|
||||
'name' => 'Rating',
|
||||
'type' => 'rating',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
'rating_max_value' => 5
|
||||
],
|
||||
[
|
||||
'name' => 'Scale',
|
||||
'type' => 'scale',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
'scale_min_value' => 1,
|
||||
'scale_max_value' => 10,
|
||||
'scale_step_value' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'Slider',
|
||||
'type' => 'slider',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
'slider_min_value' => 1,
|
||||
'slider_max_value' => 100,
|
||||
'slider_step_value' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'Select',
|
||||
'type' => 'select',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
'allow_creation' => false,
|
||||
'select' => [
|
||||
'options' => [['id' => 'First', 'name' => 'First'], ['id' => 'Second', 'name' => 'Second']],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Multi Select',
|
||||
'type' => 'multi_select',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
'allow_creation' => false,
|
||||
'multi_select' => [
|
||||
'options' => [['id' => 'One', 'name' => 'One'], ['id' => 'Two', 'name' => 'Two'], ['id' => 'Three', 'name' => 'Three']],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'Date',
|
||||
'type' => 'date',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
],
|
||||
[
|
||||
'name' => 'Checkbox',
|
||||
'type' => 'checkbox',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
],
|
||||
[
|
||||
'name' => 'URL',
|
||||
'type' => 'url',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
],
|
||||
[
|
||||
'name' => 'Email',
|
||||
'type' => 'email',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
],
|
||||
[
|
||||
'name' => 'Phone Number',
|
||||
'type' => 'phone_number',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
],
|
||||
[
|
||||
'name' => 'Files',
|
||||
'type' => 'files',
|
||||
'hidden' => false,
|
||||
'required' => false,
|
||||
],
|
||||
];
|
||||
|
||||
return Form::factory()
|
||||
->withProperties(FormFactory::formatProperties($dbProperties))
|
||||
->forWorkspace($workspace)
|
||||
->createdBy($user)
|
||||
->make($data);
|
||||
}
|
||||
|
||||
public function createForm(User $user, Workspace $workspace, array $data = [])
|
||||
{
|
||||
$form = $this->makeForm($user, $workspace, $data);
|
||||
$form->save();
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
public function createUser(array $data = [])
|
||||
{
|
||||
return \App\Models\User::factory()->create($data);
|
||||
}
|
||||
|
||||
public function createProUser()
|
||||
{
|
||||
$user = $this->createUser();
|
||||
|
||||
$user->subscriptions()->create([
|
||||
'type' => 'default',
|
||||
'stripe_id' => Str::random(),
|
||||
'stripe_status' => 'active',
|
||||
'stripe_price' => Str::random(),
|
||||
'quantity' => 1,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function createTrialingUser()
|
||||
{
|
||||
$user = $this->createUser();
|
||||
$user->subscriptions()->create([
|
||||
'name' => 'default',
|
||||
'stripe_id' => Str::random(),
|
||||
'stripe_status' => 'trialing',
|
||||
'stripe_price' => Str::random(),
|
||||
'trial_ends_at' => now()->addDays(5),
|
||||
'quantity' => 1,
|
||||
]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function actingAsUser(?User $user = null)
|
||||
{
|
||||
if ($user == null) {
|
||||
$user = $this->createUser();
|
||||
}
|
||||
|
||||
$this->postJson('/login', [
|
||||
'email' => $user->email,
|
||||
'password' => 'password',
|
||||
])->assertSuccessful();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a user with a Pro subscription
|
||||
*
|
||||
* @return User|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model|null
|
||||
*/
|
||||
public function actingAsProUser(?User $user = null)
|
||||
{
|
||||
if ($user == null) {
|
||||
$user = $this->createProUser();
|
||||
}
|
||||
|
||||
return $this->actingAsUser($user);
|
||||
}
|
||||
|
||||
public function actingAsTrialingUser(User $user = null)
|
||||
{
|
||||
if ($user == null) {
|
||||
$user = $this->createTrialingUser();
|
||||
}
|
||||
|
||||
return $this->actingAsUser($user);
|
||||
}
|
||||
|
||||
public function actingAsGuest()
|
||||
{
|
||||
if (Auth::check()) {
|
||||
Auth::logout();
|
||||
}
|
||||
$this->assertGuest();
|
||||
}
|
||||
|
||||
public function createFormIntegration($integrationId, $formId, $settings = [])
|
||||
{
|
||||
$data = [
|
||||
'status' => true,
|
||||
'integration_id' => $integrationId,
|
||||
'logic' => null,
|
||||
'settings' => $settings
|
||||
];
|
||||
|
||||
$response = $this->postJson(route('open.forms.integration.create', $formId), $data)
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'type' => 'success',
|
||||
'message' => 'Form Integration was created.'
|
||||
]);
|
||||
|
||||
return (object) $response->json('form_integration.data');
|
||||
}
|
||||
}
|
||||
42
api/tests/Unit/Rules/StorageFileTest.php
Normal file
42
api/tests/Unit/Rules/StorageFileTest.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
it('can validate file types', function () {
|
||||
Storage::shouldReceive('exists')
|
||||
->andReturn(true);
|
||||
Storage::shouldReceive('size')
|
||||
->andReturn(1000000);
|
||||
|
||||
$validator = new \App\Rules\StorageFile(1000000, ['jpg', 'JPEG', 'png']);
|
||||
collect([
|
||||
'file_name_' . Str::uuid() . '.jpg',
|
||||
'file_name_' . Str::uuid() . '.png',
|
||||
'file_name_' . Str::uuid() . '.JPG',
|
||||
'file_name_' . Str::uuid() . '.JPEG'
|
||||
])->each(function ($file) use ($validator) {
|
||||
$this->assertTrue($validator->passes('file', $file));
|
||||
});
|
||||
|
||||
$this->assertFalse($validator->passes('file', 'file_name_' . Str::uuid() . '.pdf'));
|
||||
});
|
||||
|
||||
it('can validate file size', function () {
|
||||
Storage::shouldReceive('exists')
|
||||
->andReturn(true);
|
||||
Storage::shouldReceive('size')
|
||||
->andReturn(1000000);
|
||||
|
||||
$validator = new \App\Rules\StorageFile(1000000);
|
||||
$this->assertTrue($validator->passes('file', 'file_name_' . Str::uuid() . '.jpg'));
|
||||
|
||||
Storage::clearResolvedInstances();
|
||||
Storage::shouldReceive('exists')
|
||||
->andReturn(true)
|
||||
->shouldReceive('size')
|
||||
->andReturn(2000000);
|
||||
|
||||
// Fake pdf with 2 times the authorized size
|
||||
$this->assertFalse($validator->passes('file', 'file_name_' . Str::uuid() . '.pdf'));
|
||||
});
|
||||
110
api/tests/Unit/Service/Forms/FormLogicPropertyResolverTest.php
Normal file
110
api/tests/Unit/Service/Forms/FormLogicPropertyResolverTest.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
use App\Service\Forms\FormLogicPropertyResolver;
|
||||
|
||||
it('can validate form logic property resolver', function ($property, $formData, $expectedResult) {
|
||||
$isRequired = FormLogicPropertyResolver::isRequired($property, $formData);
|
||||
expect($isRequired)->toBe($expectedResult);
|
||||
})->with([
|
||||
[
|
||||
[
|
||||
'id' => 'title',
|
||||
'name' => 'Name',
|
||||
'type' => 'text',
|
||||
'hidden' => false,
|
||||
'required' => true,
|
||||
'logic' => [
|
||||
'conditions' => [
|
||||
'operatorIdentifier' => 'and',
|
||||
'children' => [
|
||||
[
|
||||
'identifier' => 'user',
|
||||
'value' => [
|
||||
'operator' => 'is_not_empty',
|
||||
'property_meta' => [
|
||||
'id' => '93ea3198-353f-440b-8dc9-2ac9a7bee124',
|
||||
'type' => 'select',
|
||||
],
|
||||
'value' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'actions' => ['make-it-optional'],
|
||||
],
|
||||
],
|
||||
['93ea3198-353f-440b-8dc9-2ac9a7bee124' => ['One']],
|
||||
false,
|
||||
],
|
||||
[
|
||||
[
|
||||
'id' => 'title',
|
||||
'name' => 'Name',
|
||||
'type' => 'text',
|
||||
'hidden' => false,
|
||||
'required' => true,
|
||||
'logic' => [
|
||||
'conditions' => [
|
||||
'operatorIdentifier' => 'and',
|
||||
'children' => [
|
||||
[
|
||||
'identifier' => 'user',
|
||||
'value' => [
|
||||
'operator' => 'is_not_empty',
|
||||
'property_meta' => [
|
||||
'id' => '93ea3198-353f-440b-8dc9-2ac9a7bee124',
|
||||
'type' => 'select',
|
||||
],
|
||||
'value' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'actions' => ['make-it-optional'],
|
||||
],
|
||||
],
|
||||
['93ea3198-353f-440b-8dc9-2ac9a7bee124' => []],
|
||||
true,
|
||||
],
|
||||
[
|
||||
[
|
||||
'id' => 'title',
|
||||
'name' => 'Name',
|
||||
'type' => 'text',
|
||||
'hidden' => false,
|
||||
'required' => true,
|
||||
'logic' => [
|
||||
'conditions' => [
|
||||
'operatorIdentifier' => 'or',
|
||||
'children' => [
|
||||
[
|
||||
'identifier' => 'user',
|
||||
'value' => [
|
||||
'operator' => 'is_not_empty',
|
||||
'property_meta' => [
|
||||
'id' => '93ea3198-353f-440b-8dc9-2ac9a7bee124',
|
||||
'type' => 'select',
|
||||
],
|
||||
'value' => true,
|
||||
],
|
||||
],
|
||||
[
|
||||
'identifier' => 'email',
|
||||
'value' => [
|
||||
'operator' => 'contains',
|
||||
'property_meta' => [
|
||||
'id' => '93ea3198-353f-440b-8dc9-2ac9a7bee222',
|
||||
'type' => 'email',
|
||||
],
|
||||
'value' => 'abc',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'actions' => ['make-it-optional'],
|
||||
],
|
||||
],
|
||||
['93ea3198-353f-440b-8dc9-2ac9a7bee124' => [], '93ea3198-353f-440b-8dc9-2ac9a7bee222' => ['abc']],
|
||||
false,
|
||||
],
|
||||
]);
|
||||
37
api/tests/Unit/Service/Storage/StorageFileNameParserTest.php
Normal file
37
api/tests/Unit/Service/Storage/StorageFileNameParserTest.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
uses(\Tests\TestCase::class);
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
it('can parse filenames', function () {
|
||||
$fileName = 'Notion_app_logo_85e16d7b-58ed-43bc-8dce-7d3ff7d69f41.png';
|
||||
$parsedFilename = \App\Service\Storage\StorageFileNameParser::parse($fileName);
|
||||
expect($parsedFilename->fileName)->toBe('Notion_app_logo');
|
||||
expect($parsedFilename->uuid)->toBe('85e16d7b-58ed-43bc-8dce-7d3ff7d69f41');
|
||||
expect($parsedFilename->extension)->toBe('png');
|
||||
expect($parsedFilename->getMovedFileName())->toBe($fileName);
|
||||
|
||||
$uuid = Str::uuid()->toString();
|
||||
$parsedFilename = \App\Service\Storage\StorageFileNameParser::parse($uuid);
|
||||
expect($parsedFilename->uuid)->toBe($uuid);
|
||||
expect($parsedFilename->fileName)->toBeNull();
|
||||
expect($parsedFilename->extension)->toBeNull();
|
||||
expect($parsedFilename->getMovedFileName())->toBe($uuid);
|
||||
|
||||
$randomString = Str::random(20);
|
||||
$parsedFilename = \App\Service\Storage\StorageFileNameParser::parse($randomString);
|
||||
expect($parsedFilename->fileName)->toBeNull();
|
||||
expect($parsedFilename->uuid)->toBeNull();
|
||||
expect($parsedFilename->extension)->toBeNull();
|
||||
expect($parsedFilename->getMovedFileName())->toBeNull();
|
||||
});
|
||||
|
||||
it('can clean non-utf characters', function () {
|
||||
$fileName = 'Образец_для_заполнения_85e16d7b-58ed-43bc-8dce-7d3ff7d69f41.png';
|
||||
$parsedFilename = \App\Service\Storage\StorageFileNameParser::parse($fileName);
|
||||
expect($parsedFilename->fileName)->toBe('Образец_для_заполнения');
|
||||
expect($parsedFilename->uuid)->toBe('85e16d7b-58ed-43bc-8dce-7d3ff7d69f41');
|
||||
expect($parsedFilename->extension)->toBe('png');
|
||||
expect($parsedFilename->getMovedFileName())->toBe('___85e16d7b-58ed-43bc-8dce-7d3ff7d69f41.png');
|
||||
});
|
||||
23
api/tests/Unit/TestHelpersTest.php
Normal file
23
api/tests/Unit/TestHelpersTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
uses(\Tests\TestCase::class);
|
||||
|
||||
it('can create pro user who are subscribed', function () {
|
||||
$user = $this->actingAsProUser();
|
||||
expect($user->is_subscribed)->toBeTrue();
|
||||
});
|
||||
|
||||
it('can create test workspace', function () {
|
||||
$user = $this->actingAsProUser();
|
||||
$this->createUserWorkspace($user);
|
||||
expect($user->workspaces()->count())->toBe(1);
|
||||
});
|
||||
|
||||
it('can make a form for a database', function () {
|
||||
$user = $this->actingAsProUser();
|
||||
$workspace = $this->createUserWorkspace($user);
|
||||
$form = $this->makeForm($user, $workspace);
|
||||
expect($form->title)->not()->toBeNull();
|
||||
expect($form->description)->not()->toBeNull();
|
||||
expect(count($form->properties))->not()->toBe(0);
|
||||
});
|
||||
Reference in New Issue
Block a user