Переглянути джерело

Page, Browser and Result working, looks like !

George S. Baugh 5 роки тому
батько
коміт
2c026728f8
4 змінених файлів з 136 додано та 42 видалено
  1. 8 8
      bin/playwright.js
  2. 30 18
      lib/Playwright.pm
  3. 16 16
      lib/Playwright/Page.pm
  4. 82 0
      lib/Playwright/Result.pm

+ 8 - 8
bin/playwright.js

@@ -63,7 +63,9 @@ var pages = {};
 var responses = {};
 
 //XXX this is probably a race but I don't care yet
-(async () => {
+app.use(express.json())
+
+app.get('/session', async (req, res) => {
     if (argv._.includes('firefox')) {
         browser = await firefox.launch( { "headless" : !argv.visible } );
     }
@@ -79,17 +81,13 @@ var responses = {};
         process.exit(1);
     }
     pages.default = await browser.newPage();
-    pages.default.goto('http://google.com');
 
     if (argv.debug) {
         console.log('Browser Ready for use');
     }
+    res.json({ error: false, message: 'Browser started successfully.' });
+});
 
-})();
-
-
-
-app.use(express.json())
 app.get('/command', async (req, res) => {
 
 	var payload = req.query;
@@ -130,7 +128,9 @@ app.get('/command', async (req, res) => {
 });
 
 app.get('/shutdown', async (req, res) => {
-    await browser.close();
+    if (browser) {
+        await browser.close();
+    }
     res.json( { error: false, message : "Sent kill signal to browser" });
     process.exit(0);
 });

+ 30 - 18
lib/Playwright.pm

@@ -69,6 +69,19 @@ Creates a new browser and returns a handle to interact with it, along with a new
 
 our ($spec, $server_bin, %class_spec);
 
+my %transmogrify = (
+    Page   => sub { 
+        my ($self, $res) = @_;
+        require Playwright::Page;
+        return Playwright::Page->new(   browser => $self, page => $res->{_guid} );
+    },
+    Result => sub {
+        my ($self, $res) = @_;
+        require Playwright::Response;
+        return Playwright::Response->new( browser => $self, id   => $res->{_guid} );
+    },
+);
+
 BEGIN {
     my $path2here = File::Basename::dirname(Cwd::abs_path($INC{'Playwright.pm'}));
     my $specfile = "$path2here/../api.json";
@@ -85,7 +98,7 @@ BEGIN {
     # Install the subroutines if they aren't already
     foreach my $method (keys(%class_spec)) {
         Sub::Install::install_sub({
-            code => sub { _request(@_) },
+            code => sub { _request(shift, \%transmogrify, args => [@_], command => $method ) },
             as   => $method,
         });
     }
@@ -110,6 +123,11 @@ sub new ($class, %options) {
         pid     => _start_server($options{browser},$options{visible}, $port, $options{debug}),
     }, $class);
 
+    my $res = $self->_request( \%transmogrify, url => 'session' );
+    use Data::Dumper;
+    print Dumper($res);
+    confess("Could not create new session") if $res->{error};
+
     return ($self, Playwright::Page->new( browser => $self, page => 'default' ));
 }
 
@@ -134,7 +152,7 @@ Automatically called when the Playwright object goes out of scope.
 =cut
 
 sub quit ($self) {
-    $self->_request( url => 'shutdown' );
+    $self->_request( \%transmogrify, url => 'shutdown' );
     return waitpid($self->{pid},0);
 }
 
@@ -147,26 +165,20 @@ sub _start_server($browser,$visible, $port, $debug) {
     $visible = $visible ? '-v' : '';
     $debug   = $debug   ? '-d' : '';
 
+    $ENV{DEBUG} = 'pw:api';
     my $pid = fork // confess("Could not fork");
-    return $pid if $pid;
+    if ($pid) {
+        print "Waiting for port to come up..." if $debug;
+        Net::EmptyPort::wait_port($port,30) or confess("Server never came up after 30s!");
+        print "done\n" if $debug;
+        return $pid;
+    }
 
     exec( $server_bin, $browser, $visible, "-p", $port, $debug);
 }
 
-my %transmogrify = (
-    Page   => sub { 
-        my ($self, $res) = @_;
-        require Playwright::Page;
-        return Playwright::Page->new(   browser => $self, page => $res->{_guid} );
-    },
-    Result => sub {
-        my ($self, $res) = @_;
-        require Playwright::Result;
-        return Playwright::Result->new( browser => $self, id   => $res->{_guid} );
-    },
-);
-
-sub _request ($self, %args) {
+sub _request ($self, $translator, %args) {
+    $translator //= \%transmogrify;
     my $qq = URI::Query->new(%args);
     my $url = $args{url} // 'command';
     my $fullurl = "http://localhost:$self->{port}/$url?$qq";
@@ -175,7 +187,7 @@ sub _request ($self, %args) {
     my $response = $self->{ua}->request($request);
     my $decoded  = JSON::MaybeXS::decode_json($response->decoded_content());
     
-    return $transmogrify{$decoded->{_type}}->($self,$decoded) if $decoded->{_type} && exists $transmogrify{$decoded->{_type}};
+    return $translator->{$decoded->{_type}}->($self,$decoded) if $decoded->{_type} && exists $translator->{$decoded->{_type}};
     return $decoded;
 }
 

+ 16 - 16
lib/Playwright/Page.pm

@@ -43,6 +43,19 @@ Creates a new page and returns a handle to interact with it, along with a Playwr
 
 =cut
 
+my %transmogrify = (
+    Frame         => sub {
+        my ($self, $res) = @_;
+        require Playwright::Frame;
+        return Playwright::Frame->new(   page => $self, frame => $res->{_guid} );
+    },
+    ElementHandle => sub {
+        my ($self, $res) = @_;
+        require Playwright::Element;
+        return Playwright::Element->new( page => $self, id    => $res->{_guid} ); 
+    },
+);
+
 sub new ($class, %options) {
 
     my $self = bless({
@@ -54,7 +67,7 @@ sub new ($class, %options) {
     # Install the subroutines if they aren't already
     foreach my $method (keys(%{$self->{spec}})) {
         Sub::Install::install_sub({
-            code => sub { _request(@_) },
+            code => sub { _request(shift, \%transmogrify, args => [@_], command => $method, page => $self->{guid} ) },
             as   => $method,
         }) unless $self->can($method);
     }
@@ -74,22 +87,9 @@ sub spec ($self) {
     return %{$self->{spec}};
 }
 
-my %transmogrify = (
-    Frame         => sub {
-        my ($self, $res) = @_;
-        require Playwright::Frame;
-        return Playwright::Frame->new(   page => $self, frame => $res->{_guid} );
-    },
-    ElementHandle => sub {
-        my ($self, $res) = @_;
-        require Playwright::Element;
-        return Playwright::Element->new( page => $self, id    => $res->{_guid} ); 
-    },
-);
-
-sub _request ($self,%options) {
+sub _request ($self,$translator, %options) {
     $options{page} = $self->{guid};
-    return $self->SUPER::_request(%options);
+    return $self->{browser}->_request($translator, %options);
 }
 
 1;

+ 82 - 0
lib/Playwright/Result.pm

@@ -0,0 +1,82 @@
+package Playwright::Response;
+
+use strict;
+use warnings;
+
+use Sub::Install();
+use Carp qw{confess};
+
+#ABSTRACT: Object representing Playwright network responses
+
+no warnings 'experimental';
+use feature qw{signatures state};
+
+=head2 SYNOPSIS
+
+    use Playwright;
+    my ($browser,$page) = Playwright->new( browser => "chrome" );
+    my $res = $page->goto('http://www.google.com');
+    print $res->url;
+
+=head2 DESCRIPTION
+
+Perl interface to a lightweight node.js webserver that proxies commands runnable by Playwright in the 'Page' Class.
+See L<https://playwright.dev/#version=v1.5.1&path=docs%2Fapi.md&q=class-page> for more information.
+
+The specification for this class can also be inspected with the 'spec' method:
+
+    use Data::Dumper;
+    use Playwright::Response;
+    my $page = Playwright::Response->new(...);
+    print Dumper($page->spec);
+
+=head1 CONSTRUCTOR
+
+=head2 new(HASH) = (Playwright,Playwright::Frame)
+
+Creates a new page and returns a handle to interact with it, along with a Playwright::Frame (the main Frame) to interact with (supposing the page is a FrameSet).
+
+=head3 INPUT
+
+    browser (Playwright) : Playwright object.
+    page (STRING) : _guid returned by a response from the Playwright server with _type of 'Page'.
+
+=cut
+
+sub new ($class, %options) {
+
+    my $self = bless({
+        spec    => $options{browser}{spec}{Response}{members},
+        browser => $options{browser},
+        guid    => $options{id},
+    }, $class);
+
+    # Install the subroutines if they aren't already
+    foreach my $method (keys(%{$self->{spec}})) {
+        Sub::Install::install_sub({
+            code => sub { _request(shift, undef, args => [@_], command => $method, result => $self->{guid} ) },
+            as   => $method,
+        }) unless $self->can($method);
+    }
+
+    return ($self);
+}
+
+=head1 METHODS
+
+=head2 spec
+
+Return the relevant methods and their definitions for this module which are built dynamically from the Playwright API spec.
+
+=cut
+
+sub spec ($self) {
+    return %{$self->{spec}};
+}
+
+sub _request ($self,$translator, %options) {
+    $options{result} = $self->{guid};
+    return $self->{browser}->_request($translator, %options);
+}
+
+1;