cloudcreativity / json-api-testing Goto Github PK
View Code? Open in Web Editor NEWPHPUnit test helpers to check JSON API documents.
License: MIT License
PHPUnit test helpers to check JSON API documents.
License: MIT License
Both the assertCreatedWithServerId
and assertCreatedWithClientId
expect the Location
header to be present. However, if there is a resource that is not retrievable via its ID, then it would be legitimate to not have a Location
header. The assertion therefore needs to accept null
for the expected location.
This fits with the spec, that states that the Location header SHOULD be included... i.e. it is legitimate not to have the header.
When using the provided testing methods, the following exception is always thrown:
CloudCreativity\LaravelJsonApi\Exceptions\RuntimeException: JSON API resource type is not registered.
When I changed the parameter function in the CloudCreativity\LaravelJsonApi\Routing\Route
class to call \Route::current()
instead of $this->route
, the issue is resolved. I believe the Route class is not properly loading in the current route, as the local $this->route
property is always null
.
Regular HTTP calls to the api work as expected - the exception is only thrown when running PHPUnit tests.
Here is my example test:
class EventsTest extends TestCase
{
/**
* @var string
*/
protected $resourceType = 'events';
/**
* A basic test example.
*
* @return void
*/
public function testSearch()
{
factory(\App\Models\Event::class, 2)->create();
$this->doSearch([
'page' => ['number' => 1, 'size' => 10],
])->assertSearchedMany();
}
}
And here is the exception stack trace:
[2019-08-06 14:39:52] testing.ERROR: JSON API resource type is not registered. {"exception":"[object] (CloudCreativity\\LaravelJsonApi\\Exceptions\\RuntimeException(code: 0): JSON API resource type is not registered. at C:\\Users\\brian\\Code\\acesandaros\\vendor\\cloudcreativity\\laravel-json-api\\src\\Routing\\Route.php:178)
[stacktrace]
#0 C:\\Users\\brian\\Code\\acesandaros\\vendor\\cloudcreativity\\laravel-json-api\\src\\Routing\\Route.php(152): CloudCreativity\\LaravelJsonApi\\Routing\\Route->getTypes()
#1 C:\\Users\\brian\\Code\\acesandaros\\vendor\\cloudcreativity\\laravel-json-api\\src\\Http\\Middleware\\Authorize.php(84): CloudCreativity\\LaravelJsonApi\\Routing\\Route->getType()
#2 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(163): CloudCreativity\\LaravelJsonApi\\Http\\Middleware\\Authorize->handle(Object(Illuminate\\Http\\Request), Object(Closure), Object(App\\JsonApi\\v2\\DefaultAuthorizer))
#3 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#4 C:\\Users\\brian\\Code\\acesandaros\\vendor\\cloudcreativity\\laravel-json-api\\src\\Http\\Middleware\\BootJsonApi.php(78): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#5 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(163): CloudCreativity\\LaravelJsonApi\\Http\\Middleware\\BootJsonApi->handle(Object(Illuminate\\Http\\Request), Object(Closure), 'v2')
#6 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#7 C:\\Users\\brian\\Code\\acesandaros\\vendor\\barryvdh\\laravel-cors\\src\\HandleCors.php(36): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#8 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(163): Barryvdh\\Cors\\HandleCors->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#9 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#10 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Middleware\\SubstituteBindings.php(41): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#11 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(163): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#12 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#13 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Middleware\\ThrottleRequests.php(58): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#14 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(163): Illuminate\\Routing\\Middleware\\ThrottleRequests->handle(Object(Illuminate\\Http\\Request), Object(Closure), 60, '1')
#15 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#16 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(104): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#17 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(682): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#18 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(657): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))
#19 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(623): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))
#20 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(612): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))
#21 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(176): Illuminate\\Routing\\Router->dispatch(Object(Illuminate\\Http\\Request))
#22 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(30): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))
#23 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\
ova\\src\\Http\\Middleware\\ServeNova.php(26): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#24 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(163): Laravel\\Nova\\Http\\Middleware\\ServeNova->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#25 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#26 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php(21): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#27 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(163): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#28 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#29 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php(21): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#30 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(163): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#31 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#32 C:\\Users\\brian\\Code\\acesandaros\\app\\Http\\Middleware\\RedirectWWWRequests.php(25): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#33 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(163): App\\Http\\Middleware\\RedirectWWWRequests->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#34 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#35 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize.php(27): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#36 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(163): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#37 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#38 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode.php(62): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#39 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(163): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#40 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#41 C:\\Users\\brian\\Code\\acesandaros\\vendor\\barryvdh\\laravel-cors\\src\\HandlePreflight.php(29): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#42 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(163): Barryvdh\\Cors\\HandlePreflight->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#43 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#44 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(104): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#45 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(151): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#46 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(116): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))
#47 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Testing\\Concerns\\MakesHttpRequests.php(375): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))
#48 C:\\Users\\brian\\Code\\acesandaros\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Testing\\Concerns\\MakesHttpRequests.php(347): Illuminate\\Foundation\\Testing\\TestCase->call('GET', 'https://acesand...', Array, Array, Array, Array, '[]')
#49 C:\\Users\\brian\\Code\\acesandaros\\vendor\\cloudcreativity\\laravel-json-api\\src\\Testing\\MakesJsonApiRequests.php(103): Illuminate\\Foundation\\Testing\\TestCase->json('GET', 'https://acesand...', Array, Array)
#50 C:\\Users\\brian\\Code\\acesandaros\\vendor\\cloudcreativity\\laravel-json-api\\src\\Testing\\MakesJsonApiRequests.php(118): Tests\\JsonApi\\TestCase->jsonApi('GET', 'https://acesand...', Object(Illuminate\\Support\\Collection), Array, Array)
#51 C:\\Users\\brian\\Code\\acesandaros\\vendor\\cloudcreativity\\laravel-json-api\\src\\Testing\\MakesJsonApiRequests.php(190): Tests\\JsonApi\\TestCase->getJsonApi('https://acesand...', Array, Array)
#52 C:\\Users\\brian\\Code\\acesandaros\\tests\\JsonApi\\Feature\\EventsTest.php(21): Tests\\JsonApi\\TestCase->doSearch()
#53 phar://C:/bin/phpunit.phar/phpunit/Framework/TestCase.php(1084): Tests\\JsonApi\\Feature\\EventsTest->test_index()
#54 phar://C:/bin/phpunit.phar/phpunit/Framework/TestCase.php(760): PHPUnit\\Framework\\TestCase->runTest()
#55 phar://C:/bin/phpunit.phar/phpunit/Framework/TestResult.php(565): PHPUnit\\Framework\\TestCase->runBare()
#56 phar://C:/bin/phpunit.phar/phpunit/Framework/TestCase.php(537): PHPUnit\\Framework\\TestResult->run(Object(Tests\\JsonApi\\Feature\\EventsTest))
#57 phar://C:/bin/phpunit.phar/phpunit/Framework/TestSuite.php(431): PHPUnit\\Framework\\TestCase->run(Object(PHPUnit\\Framework\\TestResult))
#58 phar://C:/bin/phpunit.phar/phpunit/Framework/TestSuite.php(431): PHPUnit\\Framework\\TestSuite->run(Object(PHPUnit\\Framework\\TestResult))
#59 phar://C:/bin/phpunit.phar/phpunit/TextUI/TestRunner.php(425): PHPUnit\\Framework\\TestSuite->run(Object(PHPUnit\\Framework\\TestResult))
#60 phar://C:/bin/phpunit.phar/phpunit/TextUI/Command.php(95): PHPUnit\\TextUI\\TestRunner->doRun(Object(PHPUnit\\Framework\\TestSuite), Array, true)
#61 phar://C:/bin/phpunit.phar/phpunit/TextUI/Command.php(67): PHPUnit\\TextUI\\Command->run(Array, true)
#62 C:\\bin\\phpunit.phar(644): PHPUnit\\TextUI\\Command::main()
#63 {main}
"}
Is there anything I might have missed when setting up the package?
Currently it's difficult to test that no resource are included. The only way I found so far is:
$response->getDocument()->assertNull('/included');
That's not very ergonomic especially compared to $response->assertIsIncluded()
, $response->assertIncludes()
and $response->assertIncluded()
.
I tried $response->assertIncluded([])
but that results in an error that expected []
does not equal null
. $response->assertIncluded(null)
is not allowed by argument type.
I noticed that assertFetchedMany
supports Illuminate\Support\Collection
while assertIncluded
does not.
json-api-testing/src/Concerns/HasHttpAssertions.php
Lines 485 to 495 in 28dc994
json-api-testing/src/Concerns/HasHttpAssertions.php
Lines 167 to 174 in 28dc994
This is not very intuitive. Not sure about the trade-offs but it would be great if all methods support any iterable
and not only array
.
In HttpAssert::assertServerGeneratedId()
an exception is thrown if the expected resource object has an id
member.
Normally this would be the case - i.e. the test would not know what id the server will issue.
However, there may be some cases where the test does know the id the server will issue - for example, if the creation occurs via a service and that service is mocked.
It would be best to allow an id to be passed in to this assertion. At the end of the assertion chain in the method, it calls assertExists
to check a /data/id
member exists. If an id has been provided, rather than asserting it exists, it could assert it is the expected id value.
The assertDeleted
method just calls either the assertNoContent
or assertMetaWithoutData
methods. As per #15, it would just be simpler if the developer called the actual method for the response that they are expecting.
We can therefore deprecate assertDeleted
and remove it in the next major release.
At the moment the expected location when calling assertCreatedWithClientId
must not contain the expected id. This is because the assertion reads the id
from the expected resource array and appends it to the provided URI.
However, this doesn't read nicely in tests. For example:
$post = Post::factory()->make();
$data = [
'type' => 'posts',
'id' => '7088eccc-a7cd-46f6-81f9-c553c9065dbd',
'attributes' => [
'content' => $post->content,
'slug' => $post->slug,
'title' => $post->title,
],
];
$response = $this
->jsonApi()
->expects('posts')
->withData($data)
->post('/api/v1/posts', $data);
$response->assertCreatedWithClientId(
'http://localhost/api/v1/posts',
$data
);
I think it reads better to do this:
$response->assertCreatedWithClientId(
'http://localhost/api/v1/posts/7088eccc-a7cd-46f6-81f9-c553c9065dbd',
$data
);
To fix in a non-breaking way, it would be good if the assertion accepted either. i.e. it can read the id
from the provided $data
, and check whether the URI already contains that id
. If not, it can append it.
The assertUpdated
method just calls either assertFetchedOne
or assertNoContent
. As it has no added value, it is actually a bit misleading - as it makes it sound like there are particular things that need to be asserted for an update request. (For example, the create assertions are useful because they also assert a Location
header.)
We should deprecate this method and remove it in the next major release.
Hi,
in first thank you for this handy package. It saves me lot of time.
This is only question about possibility to have this feature.
As in phpunit there you can do something like:
$this->assertEquals( 5, 6, "Multiplying 2 and 3 did not return 6");
Implementation of $message variable can be seen in PHPUnit\Framework\Assert class.
source: http://www.kreamer.org/phpunit-cookbook/1.0/assertions/display-useful-message-when-test-fails
I am just writing some integration tests that covers authorization testing. If the test fails then there is error in role settings in app. It can be handy to show info in console like:
$this->doRead($testingSubject)->assertStatus(403, 'In most cases this is wrong role settings in Bouncer');
This is only idea :).
Thanks.
Hi,
I'm trying out laravel-json-api at the moment and it looks very promising.
The only thing that bugged me a little so far is that I had to downgrade PHPUnit from 8.0 back to 7.0 (Laravel 5.8 optionally allows to upgrade to PHPUnit 8.0) to be able to use the test helpers.
I wonder how much of a pain it'd be for this package to also support PHPUnit 8.0? (I can see it supports both 6.0 and 7.0 at the moment).
The 8.0 changelog can be found here.
Thanks!
It seems the $response->assertHasError(409);
fails as it is trying to match a subset of the response document with "status" as an integer, but the JSON-API spec requires the error "status" to be a string.
Output of test:
Failed asserting that the array at [/errors] contains the subset:
{
"status": 409
}
within JSON API document:
{
"errors": [
{
"detail": "Blah blah blah",
"status": "409",
"title": "Some Conflict"
}
]
}.
Currently the assertHasError method will only take $status as an int:
public function assertHasError(int $status, array $error = [], bool $strict = true): self
The PHPUnit diff for assertFetchedToOne
has the expected as the actual content. The expected for the diff should be the resource identifier.
Picked up on this when using the assertion when reading the related resource. The assertion correctly failed (because the content was a resource object instead of a resource identifier) but the diff was wrong.
There are no exact error assertions, whereas most of the resource assertions have exact equivalents. Need to add these.
Hi,
I'm currently upgrading a project to Laravel 9 and some tests are failing because of the newly introduced type-hints.
More specifically, calling assertOk()
now fails for endpoints returning a file download:
TypeError: CloudCreativity\JsonApi\Testing\HttpAssert::assertStatusCode(): Argument #3 ($content) must be of type ?string, bool given, called in /var/www/vendor/cloudcreativity/json-api-testing/src/Concerns/HasHttpAssertions.php on line 103
/var/www/vendor/cloudcreativity/json-api-testing/src/HttpAssert.php:58
/var/www/vendor/cloudcreativity/json-api-testing/src/Concerns/HasHttpAssertions.php:103
/var/www/vendor/laravel-json-api/testing/src/TestResponse.php:195
/var/www/vendor/laravel/framework/src/Illuminate/Testing/TestResponse.php:100
Possible solution would be to change this line for:
string|bool $content = null,
Cheers!
The assertMetaWithoutData
method expects a 200
status code - it really should just assert a success status code.
We're currently preparing for a Laravel 7 upgrade, which enables us to use PHPUnit v9.0.
Are you planning on updating the package dependencies in the near future?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.