Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .php-cs-fixer.cache
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"php":"8.2.29","version":"3.91.2:v3.91.2#f171dc216bc8a4192d5a0876a899cce6f9e379d6","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"modifier_keywords":true,"new_with_parentheses":{"anonymous_class":true},"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":{"closure_fn_spacing":"one"},"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"after_heredoc":true},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true,"octal_notation":true,"clean_namespace":true,"no_unset_cast":true,"assign_null_coalescing_to_coalesce_equal":true,"normalize_index_brace":true,"heredoc_indentation":true,"no_whitespace_before_comma_in_array":{"after_heredoc":true},"trailing_comma_in_multiline":{"after_heredoc":true},"list_syntax":true,"ternary_to_null_coalescing":true,"array_syntax":true,"no_unused_imports":true,"fully_qualified_strict_types":true},"hashes":{"src\/Command\/Router.php":"8956c9552a204df48b3825c48a7ade4c","src\/Command\/ServeCommand.php":"4c45cbcf7c8fe646c68c1ec35d9a4984","src\/Command\/RouterInterface.php":"5dd19ba932d4c43c920427003b3c1c3c","src\/Coverage\/Coverage.php":"0cb07471a183377c0b8fc1e6828cd606","src\/Util\/ProjectRootResolver.php":"cfc86290611994f3efe9355e84ae4049","src\/Util\/Composer.php":"0ece8bbf75bbb97e7d0a583404824538","src\/Util\/PhpUnitCommandExecutor.php":"84274486bc5836d4dfa6a15ae4711dcc","src\/PHPUnit\/PhpUnitHubExtension.php":"fe86b1c890e1b827fba07f738a36b24c","src\/Discoverer\/TestDiscoverer.php":"26db9dbb92284349b05b7320d1250a6f","src\/WebSocket\/StatusHandler.php":"e65bbba93f1f1c8bb116140370023aa1","src\/Http\/DecoratedHttpServer.php":"796efd5b1f3413200c4216eacd07baf4","src\/TestRunner\/TestRunner.php":"55f494bb6094e554e31388e3ba8c3431","tests\/Command\/RouterTest.php":"fcbb7a575e2103f020e0aa797dd07e7c","tests\/Command\/ServeCommandTest.php":"98e0865c6fd11eb3726bf182e37012e7","tests\/Coverage\/CoverageTest.php":"2e6a24d482ff721a9deff2f194e0e2bd","tests\/Util\/ProjectRootResolverTest.php":"b77b8208c37629acedd90b4b675f761e","tests\/Util\/ComposerTest.php":"d9c61117c9f424c3bd45724c13a9ef87","tests\/Util\/PhpUnitCommandExecutorTest.php":"2f9d8ada0f682222427c4e5689e88d98","tests\/Discoverer\/TestDiscovererTest.php":"a4354743436349d6c8fdde06e9f3e969","tests\/WebSocket\/StatusHandlerTest.php":"532eaf4611becdc32d805efc6411f665","tests\/Http\/DecoratedHttpServerTest.php":"eca8426406a227d192f817bac2853cb2","tests\/TestRunner\/TestRunnerTest.php":"529b29a3acbe2b17fd709e54cc38c3da"}}
{"php":"8.2.29","version":"3.91.2:v3.91.2#f171dc216bc8a4192d5a0876a899cce6f9e379d6","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"modifier_keywords":true,"new_with_parentheses":{"anonymous_class":true},"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":{"closure_fn_spacing":"one"},"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"after_heredoc":true},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true,"octal_notation":true,"clean_namespace":true,"no_unset_cast":true,"assign_null_coalescing_to_coalesce_equal":true,"normalize_index_brace":true,"heredoc_indentation":true,"no_whitespace_before_comma_in_array":{"after_heredoc":true},"trailing_comma_in_multiline":{"after_heredoc":true},"list_syntax":true,"ternary_to_null_coalescing":true,"array_syntax":true,"no_unused_imports":true,"fully_qualified_strict_types":true},"hashes":{"src\/Command\/Router.php":"cacf79fb8b8e11fae811aa1cb7f45844","src\/Command\/ServeCommand.php":"4c45cbcf7c8fe646c68c1ec35d9a4984","src\/Command\/RouterInterface.php":"f6cc6a3f32b5a9d8dedcb1f34a1cbd68","src\/Coverage\/Coverage.php":"0cb07471a183377c0b8fc1e6828cd606","src\/Util\/ProjectRootResolver.php":"cfc86290611994f3efe9355e84ae4049","src\/Util\/Composer.php":"0ece8bbf75bbb97e7d0a583404824538","src\/Util\/PhpUnitCommandExecutor.php":"84274486bc5836d4dfa6a15ae4711dcc","src\/PHPUnit\/PhpUnitHubExtension.php":"bc97add061d2b615a4c828142d07e905","src\/Discoverer\/TestDiscoverer.php":"93f30da5e984101dc1e402c6fdc626e2","src\/WebSocket\/StatusHandler.php":"e65bbba93f1f1c8bb116140370023aa1","src\/Http\/DecoratedHttpServer.php":"796efd5b1f3413200c4216eacd07baf4","src\/TestRunner\/TestRunner.php":"2e6e8c057e8243009b3acda9eb1a8d37","tests\/Command\/RouterTest.php":"fcbb7a575e2103f020e0aa797dd07e7c","tests\/Command\/ServeCommandTest.php":"98e0865c6fd11eb3726bf182e37012e7","tests\/Coverage\/CoverageTest.php":"2e6a24d482ff721a9deff2f194e0e2bd","tests\/Util\/ProjectRootResolverTest.php":"b77b8208c37629acedd90b4b675f761e","tests\/Util\/ComposerTest.php":"d9c61117c9f424c3bd45724c13a9ef87","tests\/Util\/PhpUnitCommandExecutorTest.php":"2f9d8ada0f682222427c4e5689e88d98","tests\/Discoverer\/TestDiscovererTest.php":"677f2f722a38617cc5bcc4e3ae7942fa","tests\/WebSocket\/StatusHandlerTest.php":"532eaf4611becdc32d805efc6411f665","tests\/Http\/DecoratedHttpServerTest.php":"eca8426406a227d192f817bac2853cb2","tests\/TestRunner\/TestRunnerTest.php":"e6eb78e9c9b57079805e066eca06c812"}}
2 changes: 1 addition & 1 deletion .phpunit.result.cache

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,42 @@ That's it! All dependencies will be installed automatically.
- The **"Results"** tab will populate in real-time as tests execute, showing you immediate feedback on test status, failures, and errors.
- Tests are grouped by their TestCase class, with failures and errors displayed prominently at the top.

### Running Tests in Parallel with ParaTeste

PHPUnit Hub supports running tests in parallel using [ParaTest](https://github.com/paratestphp/paratest). This can significantly speed up your test execution on multi-core machines.

To use ParaTest, first install it as a development dependency:

```sh
composer require --dev brianium/paratest
```

Then, you can flag on UI "Run in parallel" settings

**Generating Coverage with ParaTest**:

If you want to generate code coverage reports while running tests in parallel with ParaTest, you need to configure a `cacheDirectory` in your `phpunit.xml` or `phpunit.xml.dist` file. This is crucial for ParaTest to correctly aggregate coverage data from parallel processes.

Add the `cacheDirectory` attribute to your `<phpunit>` tag:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
cacheDirectory=".phpunit.cache"> <!-- Add this line for ParaTest coverage -->
<testsuites>
<testsuite name="default">
<directory>tests</directory>
</testsuite>
</testsuites>
<extensions>
<bootstrap class="PhpUnitHub\PHPUnit\PhpUnitHubExtension"/>
</extensions>
</phpunit>
```

### File Watching (Auto Re-run)

To automatically re-run tests whenever a source or test file changes, start the server with the `--watch` option:
Expand Down
3 changes: 2 additions & 1 deletion assets/js/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ watch(() => [
store.state.options,
store.state.selectedSuites,
store.state.selectedGroups,
store.state.coverage
store.state.coverage,
store.state.parallel
], () => {
store.saveState();
}, { deep: true });
Expand Down
1 change: 1 addition & 0 deletions assets/js/components/TestSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ async function fetchTests() {
store.state.availableSuites = data.availableSuites || [];
store.state.availableGroups = data.availableGroups || [];
store.state.coverageDriverMissing = !data.coverageDriver;
store.state.paratest = data.paratest;

// Build test index
buildTestIndex();
Expand Down
Loading