From 9842fd1544662ceac6c9511b0986fb872eb5bbc8 Mon Sep 17 00:00:00 2001 From: Fawaz IBRAHIM Date: Sat, 4 Jan 2020 23:56:26 +0100 Subject: [PATCH 1/2] Fixer premiere graphique (time series) --- api/src/Controller/MeanPriceForSquaredMeter.php | 2 +- api/src/Entity/ValeursFonciere.php | 3 --- api/src/Repository/ValeursFonciereRepository.php | 7 ++----- .../graphs/GraphsMeanPriceForSquaredMeter.js | 15 ++++++++------- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/api/src/Controller/MeanPriceForSquaredMeter.php b/api/src/Controller/MeanPriceForSquaredMeter.php index abcb6b6..6c64113 100644 --- a/api/src/Controller/MeanPriceForSquaredMeter.php +++ b/api/src/Controller/MeanPriceForSquaredMeter.php @@ -28,7 +28,7 @@ class MeanPriceForSquaredMeter extends AbstractController $metre_prices = $this->em->getRepository('App:ValeursFonciere')->getMeanPriceForSquaredMeter(); foreach ($metre_prices as &$metre_price){ $metre_price['year'] = intval($metre_price['year']); - $metre_price['month'] = intval($metre_price['month']); + //$metre_price['month'] = intval($metre_price['month']); $metre_price['mean_metre_price'] = floatval($metre_price['mean_metre_price']); } $res = new JsonResponse( diff --git a/api/src/Entity/ValeursFonciere.php b/api/src/Entity/ValeursFonciere.php index 24ad1a8..878450c 100644 --- a/api/src/Entity/ValeursFonciere.php +++ b/api/src/Entity/ValeursFonciere.php @@ -29,9 +29,6 @@ use Doctrine\ORM\Mapping as ORM; * "year"={ * "type"="number" * }, - * "month"={ - * "type"="number" - * }, * "mean_metre_price"={ * "type"="number" * } diff --git a/api/src/Repository/ValeursFonciereRepository.php b/api/src/Repository/ValeursFonciereRepository.php index acdeb2b..c63d346 100644 --- a/api/src/Repository/ValeursFonciereRepository.php +++ b/api/src/Repository/ValeursFonciereRepository.php @@ -23,7 +23,6 @@ class ValeursFonciereRepository extends ServiceEntityRepository public function getMeanPriceForSquaredMeter(){ $query = " SELECT TO_CHAR(valeurs_fonciere.date_mutation, 'YYYY') AS year, - TO_CHAR(valeurs_fonciere.date_mutation, 'MM') AS month, AVG(valeurs_fonciere.valeur_fonciere / valeurs_fonciere.surface_reelle_bati) AS mean_metre_price FROM App:ValeursFonciere AS valeurs_fonciere @@ -34,11 +33,9 @@ class ValeursFonciereRepository extends ServiceEntityRepository AND lower(valeurs_fonciere.nature_mutation) = 'vente' GROUP BY - year, - month + year ORDER BY - year, - month"; + year"; return $this->getEntityManager()->createQuery($query)->getResult(); } diff --git a/client/src/components/graphs/GraphsMeanPriceForSquaredMeter.js b/client/src/components/graphs/GraphsMeanPriceForSquaredMeter.js index 616e0c0..c6e83d5 100644 --- a/client/src/components/graphs/GraphsMeanPriceForSquaredMeter.js +++ b/client/src/components/graphs/GraphsMeanPriceForSquaredMeter.js @@ -49,7 +49,8 @@ export class GraphsMeanPriceForSquaredMeter extends Component { createBubbleChart(){ const margin = { left: 50, - bottom: 20 + bottom: 20, + top: 10 }; let data = this.state.data; let maxHeight = 0; @@ -63,12 +64,12 @@ export class GraphsMeanPriceForSquaredMeter extends Component { var width = this.container.current.clientWidth - 30, height = 600; var x = d3.scaleLinear().rangeRound([margin.left, width]); - var y = d3.scaleLinear().rangeRound([height, margin.bottom]); + var y = d3.scaleLinear().rangeRound([height - margin.top, margin.bottom]); var x_year = d3.scaleLinear().rangeRound([margin.left, width]); // Append SVG var svg = d3.select(this.svg.current).attr('width', width).attr("height", height).attr("viewBox", "0 0 " + width + " " + height); var drawAxis = function(yValueCallback, color) { - x.domain([0, data.length + 5]); + x.domain([0, data.length - 1 ]); y.domain([0, maxHeight]); x_year.domain([2014.5, 2019.5]) svg.append('path') @@ -78,13 +79,13 @@ export class GraphsMeanPriceForSquaredMeter extends Component { .attr("stroke-linejoin", "round") .attr("stroke-linecap", "round") .attr("stroke-width", 5) - .attr("d", d3.line().x(function(d) { return x(d.order); }).y(yValueCallback)) - .attr("transform", `translate(0,-${margin.bottom})`) + .attr("d", d3.line().x(function(d) { return x(d.order); }).y(yValueCallback).curve(d3.curveCatmullRom.alpha(0.5))) + .attr("transform", `translate(0,-${margin.bottom - margin.top})`) .attr("class", "time-series"); var x_axis = d3.axisBottom() .scale(x) .tickFormat("") - .tickValues([11,23,35,47]); + .tickValues([]); var y_axis = d3.axisLeft() .scale(y); var x_year_axis = d3.axisBottom() @@ -95,7 +96,7 @@ export class GraphsMeanPriceForSquaredMeter extends Component { .attr("transform", `translate(0,${height - margin.bottom})`) .call(x_axis); svg.append("g") - .attr("transform", `translate(${margin.left},-${margin.bottom})`) + .attr("transform", `translate(${margin.left},-${margin.bottom - margin.top})`) .call(y_axis); svg.append("g") .attr("transform", `translate(0,${height - margin.bottom})`) -- GitLab From fea463929b9496386b9d63699d58c6b3a78b90ca Mon Sep 17 00:00:00 2001 From: Fawaz IBRAHIM Date: Sun, 5 Jan 2020 11:38:03 +0100 Subject: [PATCH 2/2] Ajouter les tests de API --- api/.env.test | 5 + api/.gitignore | 6 + api/bin/phpunit | 13 + api/composer.json | 6 +- api/composer.lock | 347 +++++++++++++++++- api/phpunit.xml.dist | 33 ++ .../Controller/MeanPriceForSquaredMeter.php | 1 - api/symfony.lock | 31 ++ api/tests/.gitignore | 0 api/tests/ValeursFonciereTest.php | 96 +++++ 10 files changed, 529 insertions(+), 9 deletions(-) create mode 100644 api/.env.test create mode 100644 api/bin/phpunit create mode 100644 api/phpunit.xml.dist create mode 100644 api/tests/.gitignore create mode 100644 api/tests/ValeursFonciereTest.php diff --git a/api/.env.test b/api/.env.test new file mode 100644 index 0000000..d048686 --- /dev/null +++ b/api/.env.test @@ -0,0 +1,5 @@ +# define your env variables for the test env here +KERNEL_CLASS='App\Kernel' +APP_SECRET='$ecretf0rt3st' +SYMFONY_DEPRECATIONS_HELPER=999999 +PANTHER_APP_ENV=panther diff --git a/api/.gitignore b/api/.gitignore index 68e353a..bc31909 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -21,3 +21,9 @@ ### PHP Storm Files ### .DS_Store .idea + +###> symfony/phpunit-bridge ### +.phpunit +.phpunit.result.cache +/phpunit.xml +###< symfony/phpunit-bridge ### diff --git a/api/bin/phpunit b/api/bin/phpunit new file mode 100644 index 0000000..4d1ed05 --- /dev/null +++ b/api/bin/phpunit @@ -0,0 +1,13 @@ +#!/usr/bin/env php +=5.3.3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "time": "2019-09-25T14:49:45+00:00" + }, { "name": "league/html-to-markdown", "version": "4.9.0", @@ -6409,6 +6596,59 @@ ], "time": "2018-02-15T16:58:55+00:00" }, + { + "name": "symfony/css-selector", + "version": "v4.3.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9", + "reference": "f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com", + "time": "2019-10-02T08:36:26+00:00" + }, { "name": "symfony/options-resolver", "version": "v4.3.8", @@ -6463,6 +6703,71 @@ ], "time": "2019-10-28T20:59:01+00:00" }, + { + "name": "symfony/phpunit-bridge", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/phpunit-bridge.git", + "reference": "010cf42a81e7bec744edfdef5f76d6394f4906a7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/010cf42a81e7bec744edfdef5f76d6394f4906a7", + "reference": "010cf42a81e7bec744edfdef5f76d6394f4906a7", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "conflict": { + "phpunit/phpunit": "<5.4.3" + }, + "suggest": { + "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" + }, + "bin": [ + "bin/simple-phpunit" + ], + "type": "symfony-bridge", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + }, + "thanks": { + "name": "phpunit/phpunit", + "url": "https://github.com/sebastianbergmann/phpunit" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Bridge\\PhpUnit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony PHPUnit Bridge", + "homepage": "https://symfony.com", + "time": "2019-11-28T14:20:16+00:00" + }, { "name": "symfony/process", "version": "v4.3.8", @@ -6540,6 +6845,34 @@ "description": "A pack for the Symfony web profiler", "time": "2018-12-10T12:11:44+00:00" }, + { + "name": "symfony/test-pack", + "version": "v1.0.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/test-pack.git", + "reference": "ff87e800a67d06c423389f77b8209bc9dc469def" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/test-pack/zipball/ff87e800a67d06c423389f77b8209bc9dc469def", + "reference": "ff87e800a67d06c423389f77b8209bc9dc469def", + "shasum": "" + }, + "require": { + "php": "^7.0", + "symfony/browser-kit": "*", + "symfony/css-selector": "*", + "symfony/phpunit-bridge": "*" + }, + "type": "symfony-pack", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A pack for functional and end-to-end testing within a Symfony app", + "time": "2019-06-21T06:27:32+00:00" + }, { "name": "symfony/var-dumper", "version": "v4.3.8", diff --git a/api/phpunit.xml.dist b/api/phpunit.xml.dist new file mode 100644 index 0000000..5b7c820 --- /dev/null +++ b/api/phpunit.xml.dist @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + tests + + + + + + src + + + + + + + diff --git a/api/src/Controller/MeanPriceForSquaredMeter.php b/api/src/Controller/MeanPriceForSquaredMeter.php index 6c64113..1ca2bf2 100644 --- a/api/src/Controller/MeanPriceForSquaredMeter.php +++ b/api/src/Controller/MeanPriceForSquaredMeter.php @@ -28,7 +28,6 @@ class MeanPriceForSquaredMeter extends AbstractController $metre_prices = $this->em->getRepository('App:ValeursFonciere')->getMeanPriceForSquaredMeter(); foreach ($metre_prices as &$metre_price){ $metre_price['year'] = intval($metre_price['year']); - //$metre_price['month'] = intval($metre_price['month']); $metre_price['mean_metre_price'] = floatval($metre_price['mean_metre_price']); } $res = new JsonResponse( diff --git a/api/symfony.lock b/api/symfony.lock index 0f4fb28..0030ab9 100644 --- a/api/symfony.lock +++ b/api/symfony.lock @@ -149,6 +149,9 @@ "jdorn/sql-formatter": { "version": "v1.2.17" }, + "justinrainbow/json-schema": { + "version": "5.2.9" + }, "league/csv": { "version": "9.5.0" }, @@ -212,6 +215,9 @@ "symfony/asset": { "version": "v4.3.8" }, + "symfony/browser-kit": { + "version": "v4.3.9" + }, "symfony/cache": { "version": "v4.3.8" }, @@ -234,6 +240,9 @@ "config/bootstrap.php" ] }, + "symfony/css-selector": { + "version": "v4.3.9" + }, "symfony/debug": { "version": "v4.3.8" }, @@ -243,6 +252,9 @@ "symfony/doctrine-bridge": { "version": "v4.3.8" }, + "symfony/dom-crawler": { + "version": "v4.3.9" + }, "symfony/dotenv": { "version": "v4.3.8" }, @@ -340,6 +352,22 @@ "symfony/orm-pack": { "version": "v1.0.7" }, + "symfony/phpunit-bridge": { + "version": "4.3", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "master", + "version": "4.3", + "ref": "170be6250b77b421f02e986e2853df86c7bd6516" + }, + "files": [ + ".env.test", + "bin/phpunit", + "config/bootstrap.php", + "phpunit.xml.dist", + "tests/.gitignore" + ] + }, "symfony/polyfill-intl-idn": { "version": "v1.12.0" }, @@ -411,6 +439,9 @@ "symfony/stopwatch": { "version": "v4.3.8" }, + "symfony/test-pack": { + "version": "v1.0.6" + }, "symfony/translation-contracts": { "version": "v1.1.7" }, diff --git a/api/tests/.gitignore b/api/tests/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/api/tests/ValeursFonciereTest.php b/api/tests/ValeursFonciereTest.php new file mode 100644 index 0000000..41ce300 --- /dev/null +++ b/api/tests/ValeursFonciereTest.php @@ -0,0 +1,96 @@ +setName("Testing /mean-price-for-squared-meter route"); + $response = self::createClient()->request('GET', '/mean-price-for-squared-meter'); + $this->assertResponseIsSuccessful(); + $this->assertResponseHeaderSame('content-type', 'application/json'); + $this->assertStringContainsString('"year":2019', $response->getContent()); + $this->assertMatchesJsonSchema([ + "type" => "array", + "items" => [ + "type" => "object", + "properties" => [ + "year" => ["type"=>"number"], + "mean_metre_price"=> ["type"=>"number"] + ] + ] + ]); + } + + public function testNumberOfSoldByParams1(): void { + $this->setName("Testing /number-of-sold-by-params (test 1)"); + $interval = "year"; + $startDate = "2016-01-01"; + $endDate = "2018-12-31"; + $response = self::createClient()->request('GET', "/number-of-sold-by-params/{$interval}/{$startDate}/{$endDate}"); + $this->assertResponseIsSuccessful(); + $this->assertResponseHeaderSame('content-type', 'application/json'); + $this->assertStringContainsString('"year":2018', $response->getContent()); + $this->assertStringNotContainsString('"year":2019', $response->getContent()); + $this->assertMatchesJsonSchema([ + "type" => "array", + "items" => [ + "type" => "object", + "properties" => [ + "year" => ["type"=>"number"], + "number_of_sold"=> ["type"=>"number"] + ] + ] + ]); + } + + public function testNumberOfSoldByParams2(): void { + $this->setName("Testing /number-of-sold-by-params (test 2)"); + $interval = "month"; + $startDate = "2016-01-01"; + $endDate = "2018-11-30"; + $response = self::createClient()->request('GET', "/number-of-sold-by-params/{$interval}/{$startDate}/{$endDate}"); + $this->assertResponseIsSuccessful(); + $this->assertResponseHeaderSame('content-type', 'application/json'); + $this->assertStringContainsString('"year":2018', $response->getContent()); + $this->assertStringContainsString('"year":2018,"month":11', $response->getContent()); + $this->assertStringNotContainsString('"year":2018,"month":12', $response->getContent()); + $this->assertStringNotContainsString('"year":2019', $response->getContent()); + $this->assertMatchesJsonSchema([ + "type" => "array", + "items" => [ + "type" => "object", + "properties" => [ + "year" => ["type"=>"number"], + "month" => ["type"=>"number"], + "number_of_sold"=> ["type"=>"number"] + ] + ] + ]); + } + + public function testNumberOfSoldByRegion(): void { + $this->setName("Testing /number-of-sold-by-region"); + $response = self::createClient()->request('GET', "/number-of-sold-by-region"); + $this->assertResponseIsSuccessful(); + $this->assertResponseHeaderSame('content-type', 'application/json'); + $this->assertStringContainsString('"region":"Normandie"', $response->getContent()); + $this->assertMatchesJsonSchema([ + "type" => "array", + "items" => [ + "type" => "object", + "properties" => [ + "region" => ["type"=>"string"], + "count_by_region"=> ["type"=>"number"] + ] + ] + ]); + } +} -- GitLab