Skip to content

Commit

Permalink
Close rialto-php#10: Send Browser logs to the PHP logger
Browse files Browse the repository at this point in the history
  • Loading branch information
nesk committed Aug 20, 2018
1 parent e003f65 commit 574fc18
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 10 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
**Note:** PuPHPeteer is heavily based on [Rialto](https://github.com/nesk/rialto). For a complete overview of the changes, you might want to check out [Rialto's changelog](https://github.com/nesk/rialto/blob/master/CHANGELOG.md) too.

## [Unreleased]
_In progress…_
### Added
- Add a `log_browser_console` option to log the output of Browser's console methods (`console.log`, `console.debug`, `console.table`, etc…) to the PHP logger

## [1.2.0] - 2018-07-25
### Added
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,19 @@ $puppeteer = new Puppeteer;

This will create a new Node process controlled by PHP.

You can also pass some options to the constructor, see [Rialto's documentation](https://github.com/nesk/rialto/blob/master/docs/api.md#options).
You can also pass some options to the constructor, see [Rialto's documentation](https://github.com/nesk/rialto/blob/master/docs/api.md#options). PuPHPeteer also extends these options:

**Note:** If you use some timeouts higher than 30 seconds in Puppeteer's API, you will have to set a higher value for the `read_timeout` option (default: `35`):
```php
[
// Logs the output of Browser's console methods (console.log, console.debug, etc...) to the PHP logger
'log_browser_console' => false,
]
```

<details>
<summary><strong>⏱ Want to use some timeouts higher than 30 seconds in Puppeteer's API?</strong></summary> <br>

If you use some timeouts higher than 30 seconds, you will have to set a higher value for the `read_timeout` option (default: `35`):

```php
$puppeteer = new Puppeteer([
Expand All @@ -95,6 +105,7 @@ $puppeteer->launch()->newPage()->goto($url, [
'timeout' => 60000, // In milliseconds
]);
```
</details>

### No need to use the `await` keyword

Expand Down
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
"require": {
"php": ">=7.1",
"nesk/rialto": "^1.2.0",
"psr/log": "^1.0",
"vierbergenlars/php-semver": "^3.0.2"
},
"require-dev": {
"codedungeon/phpunit-result-printer": ">=0.6 <1.0",
"monolog/monolog": "^1.23",
"phpunit/phpunit": "^6.5|^7.0",
"symfony/process": "^4.0"
},
Expand Down
14 changes: 13 additions & 1 deletion src/Puppeteer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@

class Puppeteer extends AbstractEntryPoint
{
/**
* Default options.
*
* @var array
*/
protected $options = [
'read_timeout' => 30,

// Logs the output of Browser's console methods (console.log, console.debug, etc...) to the PHP logger
'log_browser_console' => false,
];

/**
* Instanciate Puppeteer's entry point.
*/
Expand All @@ -21,7 +33,7 @@ public function __construct(array $userOptions = [])
parent::__construct(
__DIR__.'/PuppeteerConnectionDelegate.js',
new PuppeteerProcessDelegate,
['read_timeout' => 35],
$this->options,
$userOptions
);
}
Expand Down
45 changes: 39 additions & 6 deletions src/PuppeteerConnectionDelegate.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
'use strict';

const puppeteer = require('puppeteer'),
Page = require('puppeteer/lib/Page'),
{Browser} = require('puppeteer/lib/Browser'),
{ConnectionDelegate} = require('@nesk/rialto');
{ConnectionDelegate} = require('@nesk/rialto'),
Logger = require('@nesk/rialto/src/node-process/Logger'),
ConsoleInterceptor = require('@nesk/rialto/src/node-process/NodeInterceptors/ConsoleInterceptor'),
StandardStreamsInterceptor = require('@nesk/rialto/src/node-process/NodeInterceptors/StandardStreamsInterceptor');

/**
* Handle the requests of a connection to control Puppeteer.
*/
class PuppeteerConnectionDelegate extends ConnectionDelegate {
class PuppeteerConnectionDelegate extends ConnectionDelegate
{
/**
* Constructor.
*
* @param {Object} options
*/
constructor() {
super();
constructor(options) {
super(options);

this.browsers = new Set;

Expand All @@ -23,8 +30,6 @@ class PuppeteerConnectionDelegate extends ConnectionDelegate {
* @inheritdoc
*/
async handleInstruction(instruction, responseHandler, errorHandler) {
const instructionName = instruction.name();

instruction.setDefaultResource(puppeteer);

let value = null;
Expand All @@ -43,9 +48,37 @@ class PuppeteerConnectionDelegate extends ConnectionDelegate {
this.browsers.add(value);
}

if (this.options.log_browser_console === true && value instanceof Page) {
value.on('console', this.logConsoleMessage);
}

responseHandler(value);
}

/**
* Log the console message.
*
* @param {ConsoleMessage} consoleMessage
*/
async logConsoleMessage(consoleMessage) {
const type = consoleMessage.type();

if (!ConsoleInterceptor.typeIsSupported(type)) {
return;
}

const level = ConsoleInterceptor.getLevelFromType(type);
const args = await Promise.all(consoleMessage.args().map(arg => arg.jsonValue()));

StandardStreamsInterceptor.startInterceptingStrings(message => {
Logger.log('Browser', level, ConsoleInterceptor.formatMessage(message));
});

ConsoleInterceptor.originalConsole[type](...args);

StandardStreamsInterceptor.stopInterceptingStrings();
}

/**
* Listen for process signal events.
*
Expand Down
26 changes: 26 additions & 0 deletions tests/PuphpeteerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,30 @@ public function check_all_resources_are_supported()

$this->markTestIncomplete($incompleteText);
}

/**
* @test
* @dontPopulateProperties browser
*/
public function browser_console_calls_are_logged()
{
$setups = [
[false, 'Received data from the port'],
[true, 'Received a Browser log:'],
];

foreach ($setups as [$logBrowserConsole, $startsWith]) {
$puppeteer = new Puppeteer([
'log_browser_console' => $logBrowserConsole,
'logger' => $this->loggerMock(
$this->at(9),
$this->isLogLevel(),
$this->stringStartsWith($startsWith)
),
]);

$this->browser = $puppeteer->launch($this->browserOptions);
$this->browser->newPage()->goto($this->url);
}
}
}
43 changes: 43 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

namespace Nesk\Puphpeteer\Tests;

use Monolog\Logger;
use ReflectionClass;
use Psr\Log\LogLevel;
use PHPUnit\Framework\Constraint\Callback;
use PHPUnit\Framework\TestCase as BaseTestCase;
use PHPUnit\Framework\MockObject\Matcher\Invocation;

class TestCase extends BaseTestCase
{
Expand All @@ -24,4 +29,42 @@ public function canPopulateProperty(string $propertyName): bool
{
return !in_array($propertyName, $this->dontPopulateProperties);
}

public function loggerMock($expectations) {
$loggerMock = $this->getMockBuilder(Logger::class)
->setConstructorArgs(['rialto'])
->setMethods(['log'])
->getMock();

if ($expectations instanceof Invocation) {
$expectations = [func_get_args()];
}

foreach ($expectations as $expectation) {
[$matcher] = $expectation;
$with = array_slice($expectation, 1);

$loggerMock->expects($matcher)
->method('log')
->with(...$with);
}

return $loggerMock;
}

public function isLogLevel(): Callback {
$psrLogLevels = (new ReflectionClass(LogLevel::class))->getConstants();
$monologLevels = (new ReflectionClass(Logger::class))->getConstants();
$monologLevels = array_intersect_key($monologLevels, $psrLogLevels);

return $this->callback(function ($level) use ($psrLogLevels, $monologLevels) {
if (is_string($level)) {
return in_array($level, $psrLogLevels, true);
} else if (is_int($level)) {
return in_array($level, $monologLevels, true);
}

return false;
});
}
}
2 changes: 2 additions & 0 deletions tests/resources/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
<h1>Example Page</h1>

<script>
console.log('Starting worker...');
new Worker('worker.js');
console.log('Worker started!');
</script>
</body>
</html>

0 comments on commit 574fc18

Please sign in to comment.