Skip to content
This repository has been archived by the owner on Dec 26, 2022. It is now read-only.

Commit

Permalink
Add Behat tests for Mandate
Browse files Browse the repository at this point in the history
* Added a Provider for creating DateTime values from strings
* Fixed a nasty bug with the DBAL DateTimeType: the convertion from database
 value to PHP value was done with the wrong timezone causing sync issues
  • Loading branch information
theofidry committed Oct 11, 2015
1 parent 6d72efa commit 250e330
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 93 deletions.
3 changes: 3 additions & 0 deletions features/api/job.feature
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ Feature: Jobs management
And the JSON should be equal to:
"""
"""

When I send a DELETE request to "/api/jobs/1"
Then the response status code should be 404

When I send a GET request to "/api/mandates/1"
Then the JSON node "jobs" should have 0 element
Expand Down
127 changes: 52 additions & 75 deletions features/api/mandate.feature
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@mandate @ignore
@mandate
Feature: Mandates management
There is a mandate for every year.
A mandate is composed of a group of users, although may not have any user.
Expand All @@ -10,81 +10,95 @@ Feature: Mandates management
A user may have one or several mandate, with or without a job.

Background:
Given the database is empty
Given the fixtures file "authentication.yml" is loaded
Given I authenticate myself as admin


Scenario: Get a collection
@crud
Scenario: It should be possible to get all mandates
Given the fixtures file "mandate/collection.yml" is loaded
When I send a GET request to "/api/mandates"
Then the response status code should be 200
And the response should be in JSON-LD
And I should get a paged collection with the context "/api/contexts/Mandate"
And the JSON node "hydra:totalItems" should be equal to 2

Scenario: Get a resource
@crud
Scenario: It should be possible to get a specific mandate
Given the fixtures file "mandate/collection.yml" is loaded
When I send a GET request to "/api/mandates/1"
Then the response status code should be 200
And the JSON node "jobs" should have 2 element
And the response should be in JSON-LD
And the JSON node "jobs" should have 3 element
Then the JSON response should have the following nodes:
| node | value | type  |
| @context | /api/contexts/Mandate | |
| @id | /api/mandates/1 | |
| @type | Mandate | |
| endAt | 2007-03-18T10:25:58+00:00 |   |
| endAt | 2006-04-17T09:38:34+00:00 |   |
| jobs | | array |
| jobs[0] | /api/jobs/4 | |
| jobs[1] | /api/jobs/51 | |
| name | Mandate 2005/2007 | |
| startAt | 2005-11-27T17:41:35+00:00 | |

| jobs[0] | /api/jobs/1 | |
| jobs[1] | /api/jobs/2 | |
| jobs[2] | /api/jobs/3 | |
| name | Mandate 2005/2006 | |
| startAt | 2005-06-25T16:43:30+00:00 | |

Scenario: Create a new resource
# With valid data
@crud
Scenario: It should be possible to create a new mandate
Given the fixtures file "mandate/job-president.yml" is loaded
When I send a POST request to "/api/mandates" with body:
"""
{
"name": "Dummy date",
"endAt": "2010-01-21T23:00:00+00:00",
"startAt": "2009-01-26T23:00:00+00:00"
"name": "My Mandate",
"startAt": "2005-08-15T15:52:01+00:00",
"endAt": "2005-12-15T15:52:01+00:00",
"jobs": [ "/api/jobs/1" ]
}
"""
Then the response status code should be 201
And the JSON node "jobs" should have 0 element
Then the JSON response should have the following nodes:
And the response status code should be 201
And the response should be in JSON-LD
And the JSON node "jobs" should have 1 element
And the JSON response should have the following nodes:
| node | value | type  |
| @context | /api/contexts/Mandate | |
| @id | /api/mandates/13 | |
| @id | /api/mandates/1 | |
| @type | Mandate | |
| endAt | 2010-01-21T23:00:00+00:00 | string  |
| name | My Mandate | |
| startAt | 2005-08-15T15:52:01+00:00 | string |
| endAt | 2005-12-15T15:52:01+00:00 | string  |
| jobs | | array |
| name | Dummy date | |
| startAt | 2009-01-26T23:00:00+00:00 | string |
| jobs[0] | /api/jobs/1 | array |

# Check if the resource has been properly persisted
When I send a GET request to "/api/mandates/13"
When I send a GET request to "/api/mandates/1"
Then the response status code should be 200
And the JSON node "jobs" should have 0 element
And the response should be in JSON-LD
And the JSON node "jobs" should have 1 element
Then the JSON response should have the following nodes:
| node | value | type  |
| @context | /api/contexts/Mandate | |
| @id | /api/mandates/1 | |
| @type | Mandate | |
| endAt | 2007-03-18T10:25:58+00:00 |   |
| jobs | | array |
| name | Mandate 2005/2007 | |
| startAt | 2005-11-27T17:41:35+00:00 | |
| node | value | type  |
| @context | /api/contexts/Mandate | |
| @id | /api/mandates/1 | |
| @type | Mandate | |
| name | My Mandate | |
| startAt | 2005-08-15T15:52:01+00:00 | string |
| endAt | 2005-12-15T15:52:01+00:00 | string  |
| jobs | | array |
| jobs[0] | /api/jobs/1 | array |

# Post again with some other valid values but no name
# Expect to have a name generated
@crud
Scenario: A mandate name is automatically picked up if none is given when creating a new mandate
When I send a POST request to "/api/mandates" with body:
"""
{
"endAt": "2051-01-21",
"startAt": "2050-01-26"
}
"""
Then the response status code should be 200
Then the response status code should be 201
And I should get a resource page with the context "/api/contexts/Mandate"
And the JSON node "name" should be equal to "Mandate 2050/2051"

# Test validation rules
@crud
Scenario: Data send for creating a mandate should be validated
When I send a POST request to "/api/mandates" with body:
"""
{
Expand All @@ -105,40 +119,3 @@ Feature: Mandates management
| violations[1] | | object |
| violations[1]->propertyPath | startAt | |
| violations[1]->message | Cette valeur ne doit pas être nulle. | |



# Scenario: If one list all the mandates, there it at least one mandate: the current one.
# #TODO
#
# Scenario: A mandate may have users.
# #TODO
#
# Scenario: It should be possible to list all the mandates.
# #TODO
#
# Scenario: It should be possible to list all the members of a given mandate.
# #TODO
#
# Scenario: It should not be possible to create a mandate unless it starts at the current year. The ending date
# should then be during the next year and may be omitted.
# #TODO
#
# Scenario: If not ending date is given for a mandate, it ends at the end of the next year.
# #TODO
#
# Scenario: If no new mandate has be created, a new one is automatically created and keep all the admin users as if
# they have a new mandate.
# #TODO
#
# Scenario: It should not be possible to delete a mandate.
# #TODO
#
# Scenario: A new member can be added to a mandate even if the mandate already ended.
# #TODO
#
# Scenario: A member may be deleted from a mandate even if the mandate already ended.
# #TODO
#
# Scenario: Once a mandate created, the dates may change but must be of the same year.
# #TODO
39 changes: 39 additions & 0 deletions features/fixtures/ORM/mandate/collection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
ApiBundle\Entity\Mandate:
mandate_2005:
startAt: <dateTimeFromFormat(DateTime::ATOM, '2005-06-25T16:43:30+00:00')>
endAt: <dateTimeFromFormat(DateTime::ATOM, '2006-04-17T09:38:34+00:00')>
jobs: [ @job_president, @job_pr, @job__1 ]

mandate_2006:
startAt: <startMandateDateTime(2006)>
endAt: <endMandateDateTime($startAt)>

ApiBundle\Entity\Job:
job (template):
title: <jobTitle()>
abbreviation: <jobAbbreviation()>
enabled: <boolean()>
#user: Should be kept unset since because is set in the user entity
#mandate: Should be kept unset since because is set in the mandate entity

job_president (extends job):
title: President
abbreviation: PR
enabled: true

job_pr (extends job):
abbreviation: PR

job__{1..9} (extends job): {}

ApiBundle\Entity\User:
user_president:
username: president.tendiserp
fullname: Président TENDISERP
email: [email protected]
roles: [ ROLE_ADMIN ]
plainPassword: guest
enabled: true
jobs: [ @job_president ]
studentConvention: ~
types: <userTypes('member')>
5 changes: 5 additions & 0 deletions features/fixtures/ORM/mandate/job-president.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ApiBundle\Entity\Job:
job_president:
title: President
abbreviation: PR
enabled: true
36 changes: 36 additions & 0 deletions src/ApiBundle/DataFixtures/Faker/Provider/DateTimeProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

/*
* This file is part of the Incipio package.
*
* (c) Théo FIDRY <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace ApiBundle\DataFixtures\Faker\Provider;

/**
* Extends {@see \Faker\Provider\DateTime}. As all method are static does not literally extend the class to avoid
* useless overhead.
*
* @author Théo FIDRY <[email protected]>
*/
class DateTimeProvider
{
/**
* Parses a string into a new DateTime object according to the specified format.
*
* @param string $format Format accepted by date().
* @param string $time String representing the time.
*
* @return \DateTime
*
* @link http://php.net/manual/en/datetime.createfromformat.php
*/
public static function dateTimeFromFormat($format, $time)
{
return \DateTime::createFromFormat($format, $time);
}
}
4 changes: 2 additions & 2 deletions src/ApiBundle/DataFixtures/Faker/Provider/MandateProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace ApiBundle\DataFixtures\Faker\Provider;

use Faker\Provider\DateTime as DateTimeProvider;
use Faker\Provider\DateTime as FakerDateTimeProvider;

/**
* Faker provider for mandates.
Expand All @@ -20,7 +20,7 @@
*
* @author Théo FIDRY <[email protected]>
*/
class MandateProvider extends DateTimeProvider
class MandateProvider extends FakerDateTimeProvider
{
/**
* Generate a datetime starting from the date given and on a period going from 3 month to 2 years.
Expand Down
25 changes: 22 additions & 3 deletions src/ApiBundle/Doctrine/DBAL/Type/UTCDateTimeType.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace ApiBundle\Doctrine\DBAL\Type;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\DateTimeType;

/**
Expand Down Expand Up @@ -40,10 +41,28 @@ public function convertToDatabaseValue($phpValue, AbstractPlatform $platform)
*/
public function convertToPHPValue($databaseValue, AbstractPlatform $platform)
{
$phpValue = parent::convertToPHPValue($databaseValue, $platform);
if (null === $databaseValue || $databaseValue instanceof \DateTime) {
return $databaseValue;
}

if ($phpValue instanceof \DateTime) {
$phpValue->setTimeZone(new \DateTimeZone('UTC'));
// The changed part is the following bloc where we put the DateTimeZone as the third argument rather than
// relying on the local timezone
$phpValue = \DateTime::createFromFormat(
$platform->getDateTimeFormatString(),
$databaseValue,
new \DateTimeZone('UTC')
);

if (false === $phpValue) {
$phpValue = date_create($databaseValue);
}

if (false === $phpValue) {
throw ConversionException::conversionFailedFormat(
$databaseValue,
$this->getName(),
$platform->getDateTimeFormatString()
);
}

return $phpValue;
Expand Down
26 changes: 25 additions & 1 deletion src/ApiBundle/Entity/Mandate.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,42 @@ public function getEndAt()
return $this->endAt;
}

/**
* @param Job[] $jobs
*
* @return $this
*
* @throws \InvalidArgumentException If jobs type is incorrect
*/
public function setJobs($jobs)
{
$this->jobs = new ArrayCollection();
foreach ($jobs as $job) {
$this->addJob($job);
}

return $this;
}

/**
* Adds Job. Will automatically update job's mandate too.
*
* @param Job $job
*
* @return $this
*
* @throws \InvalidArgumentException If job type is incorrect
*/
public function addJob(Job $job)
public function addJob($job)
{
if (false === $job instanceof Job) {
throw new \InvalidArgumentException('Unexpected type.');
}

// Check for duplication
if (false === $this->jobs->contains($job)) {
$this->jobs->add($job);
$this->jobs = new ArrayCollection(array_values($this->jobs->toArray()));
}

// Ensure the relation is bidirectional
Expand Down
4 changes: 4 additions & 0 deletions src/ApiBundle/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ services:
#
# Faker's providers
#
faker.provider.datetime:
class: ApiBundle\DataFixtures\Faker\Provider\DateTimeProvider
tags: [ { name: hautelook_alice.faker.provider } ]

faker.provider.job:
class: ApiBundle\DataFixtures\Faker\Provider\JobProvider
tags: [ { name: hautelook_alice.faker.provider } ]
Expand Down
Loading

0 comments on commit 250e330

Please sign in to comment.