Firefox-Marionette

 view release on metacpan or  search on metacpan

t/01-marionette.t  view on Meta::CPAN


if (($^O eq 'MSWin32') || ($^O eq 'cygwin')) {
} elsif ($> == 0) { # see RT#131304
       my $current = $ENV{HOME};
       my $correct = (getpwuid($>))[7];
       if ($current eq $correct) {
       } else {
               $ENV{HOME} = $correct;
               diag("Running as root.  Resetting HOME environment variable from $current to $ENV{HOME}");
               diag("Could be running in an environment where sudo does not reset the HOME environment variable, such as ubuntu");
       }
       foreach my $env_name (
				'XAUTHORITY',           # see GH#1
				'XDG_RUNTIME_DIR',      # see GH#33
                         ) {
            if ( exists $ENV{$env_name} ) {
                delete $ENV{$env_name};
                warn "Running as root.  Deleting the $env_name environment variable\n";
            }
       }
}

my @sig_nums  = split q[ ], $Config{sig_num};
my @sig_names = split q[ ], $Config{sig_name};
my %signals_by_name;
my $idx = 0;
foreach my $sig_name (@sig_names) {
	$signals_by_name{$sig_name} = $sig_nums[$idx];
	$idx += 1;
}

$SIG{INT} = sub { $terminated = 1; die "Caught an INT signal"; };
$SIG{TERM} = sub { $terminated = 1; die "Caught a TERM signal"; };

sub wait_for_server_on {
	my ($daemon, $url, $pid) = @_;
	my $host = URI->new($url)->host();
	my $port = URI->new($url)->port();
	undef $daemon;
	CONNECT: while (!IO::Socket::IP->new(Type => Socket::SOCK_STREAM(), PeerPort => $port, PeerHost => $host)) {
		diag("Waiting for server ($pid) to listen on $host:$port:$!");
		waitpid $pid, POSIX::WNOHANG();
		if (kill 0, $pid) {
			sleep 1;
		} else {
			diag("Server ($pid) has exited");
			last CONNECT;
		}
	}
	return 
}

sub empty_port {
	socket my $socket, Socket::PF_INET(), Socket::SOCK_STREAM(), 0 or die "Failed to create a socket:$!";
	bind $socket, Socket::sockaddr_in( 0, Socket::INADDR_LOOPBACK() ) or die "Failed to bind socket:$!";
	my $port = ( Socket::sockaddr_in( getsockname $socket ) )[0];
	close $socket or die "Failed to close random socket:$!";
	return $port;
}

sub process_alive {
	my ($pid) = @_;
	if ($^O eq 'MSWin32') {
		if (Win32::Process::Open(my $process, $pid, 0)) {
			$process->GetExitCode( my $exit_code );
			if ( $exit_code == Win32::Process::STILL_ACTIVE() ) {
				return 1;
			}
		} else {
			return 0;
		}
	} else {
		return kill 0, $pid;
	}
}

sub out_of_time {
	my ($package, $file, $line) = caller 1;
	if (!defined $line) {
		($package, $file, $line) = caller;
	}
	diag("Testing has been running for " . (time - $^T) . " seconds at $file line $line");
	if ($ENV{RELEASE_TESTING}) {
		return;
	} elsif (time - $^T > $test_time_limit) {
		return 1;
	} else {
		return;
	}
}

my $launches = 0;
my $ca_cert_handle;
my $ca_private_key_handle;
my $metacpan_ca_cert_handle;
my $guid_regex = qr/[a-f\d]{8}\-[a-f\d]{4}\-[a-f\d]{4}\-[a-f\d]{4}\-[a-f\d]{12}/smx;
my @old_binary_keys = (qw(firefox_binary firefox marionette));;

my ($major_version, $minor_version, $patch_version); 
sub start_firefox {
	my ($require_visible, %parameters) = @_;
	if ($terminated) {
		die "Caught a signal";
	}
	if ($ENV{FIREFOX_BINARY}) {
		my $key = shift @old_binary_keys;
		$key ||= 'binary';
		$parameters{$key} = $ENV{FIREFOX_BINARY};
		diag("Overriding firefox binary to $parameters{$key}");
	}
	if ($ENV{FIREFOX_FORCE_SCP}) {
		$parameters{scp} = 1;
	}
	if ($parameters{manual_certificate_add}) {
		delete $parameters{manual_certificate_add};
	} elsif ((defined $parameters{system_access}) && ($parameters{system_access} == 0)) {
	} elsif (defined $ca_cert_handle) {
		if ($launches % 2) {
			diag("Setting trust to list");
			$parameters{trust} = [ $ca_cert_handle->filename() ];
		} else {

t/01-marionette.t  view on Meta::CPAN

			local $TODO = $major_version < 55 ? $capabilities->browser_version() . " probably does not have support for \$firefox->window_rect()->pos_x()" : q[];
			ok(defined $old->pos_x() && $old->pos_x() =~ /^\-?\d+([.]\d+)?$/, "Window used to have a X position of " . (defined $old->pos_x() ? $old->pos_x() : q[]));
			ok(defined $old->pos_y() && $old->pos_y() =~ /^\-?\d+([.]\d+)?$/, "Window used to have a Y position of " . (defined $old->pos_y() ? $old->pos_y() : q[]));
		}
		ok($old->width() =~ /^\d+([.]\d+)?$/, "Window used to have a width of " . $old->width());
		ok($old->height() =~ /^\d+([.]\d+)?$/, "Window used to have a height of " . $old->height());
		my $new2 = $firefox->window_rect();
		TODO: {
			local $TODO = $major_version < 55 ? $capabilities->browser_version() . " probably does not have support for \$firefox->window_rect()->pos_x()" : q[];
			ok(defined $new2->pos_x() && $new2->pos_x() == $new->pos_x(), "Window has a X position of " . $new->pos_x());
			ok(defined $new2->pos_y() && $new2->pos_y() == $new->pos_y(), "Window has a Y position of " . $new->pos_y());
		}
		TODO: {
			local $TODO = $major_version >= 60 && $^O eq 'darwin' ? "darwin has dodgy support for \$firefox->window_rect()->width()" : $firefox->nightly() ? "Nightly returns incorrect values for \$firefox->window_rect()->width()" : q[];
			ok($new2->width() >= $new->width(), "Window has a width of " . $new->width() . ":" . $new2->width());
		}
		ok($new2->height() == $new->height(), "Window has a height of " . $new->height());
		TODO: {
			local $TODO = $major_version < 57 ? $capabilities->browser_version() . " probably does not have support for \$firefox->window_rect()->wstate()" : $major_version >= 66 ? $capabilities->browser_version() . " probably does not have support for \$fire...
			ok(defined $old->wstate() && $old->wstate() =~ /^\w+$/, "Window has a state of " . ($old->wstate() || q[]));
		}
		my $rect = $firefox->window_rect();
		TODO: {
			local $TODO = $major_version < 55 ? $capabilities->browser_version() . " probably does not have support for \$firefox->window_rect()->pos_x()" : q[];
			ok(defined $rect->pos_x() && $rect->pos_x() =~ /^[-]?\d+([.]\d+)?$/, "Window has a X position of " . ($rect->pos_x() || q[]));
			ok(defined $rect->pos_y() && $rect->pos_y() =~ /^[-]?\d+([.]\d+)?$/, "Window has a Y position of " . ($rect->pos_y() || q[]));
		}
		ok($rect->width() =~ /^\d+([.]\d+)?$/, "Window has a width of " . $rect->width());
		ok($rect->height() =~ /^\d+([.]\d+)?$/, "Window has a height of " . $rect->height());
	}
	my $page_timeout = 45_043;
	my $script_timeout = 48_021;
	my $implicit_timeout = 41_001;
	$new = Firefox::Marionette::Timeouts->new(page_load => $page_timeout, script => $script_timeout, implicit => $implicit_timeout);
	my $timeouts = $firefox->timeouts($new);
	ok((ref $timeouts) eq 'Firefox::Marionette::Timeouts', "\$firefox->timeouts(\$new) returns a Firefox::Marionette::Timeouts object");
	if ($ENV{RELEASE_TESTING}) {
		$firefox->restart();
		my $restart_timeouts = $firefox->timeouts();
		ok($restart_timeouts->page_load() == $page_timeout, "\$timeouts->page_load() is $page_timeout");
		ok($restart_timeouts->script() == $script_timeout, "\$timeouts->script() is $script_timeout");
		ok($restart_timeouts->implicit() == $implicit_timeout, "\$timeouts->implicit() is $implicit_timeout");
	}
	my $timeouts2 = $firefox->timeouts();
	ok((ref $timeouts2) eq 'Firefox::Marionette::Timeouts', "\$firefox->timeouts() returns a Firefox::Marionette::Timeouts object");
	ok($timeouts->page_load() == 300_000, "\$timeouts->page_load() is 5 minutes");
	ok($timeouts->script() == 30_000, "\$timeouts->script() is 30 seconds");
	ok(defined $timeouts->implicit() && $timeouts->implicit() == 0, "\$timeouts->implicit() is 0 milliseconds");
	$timeouts = $firefox->timeouts($new);
	ok($timeouts->page_load() == $page_timeout, "\$timeouts->page_load() is $page_timeout");
	ok($timeouts->script() == $script_timeout, "\$timeouts->script() is $script_timeout");
	ok($timeouts->implicit() == $implicit_timeout, "\$timeouts->implicit() is $implicit_timeout");
	if ($major_version >= $min_stealth_version) {
		TODO: {
			local $TODO = "Some installations of firefox can default to webdriver being off"; # such as http://www.cpantesters.org/cpan/report/a0532bce-c32c-11ee-ae2f-883f6e8775ea (FreeBSD 14.0-STABLE) (BuildID 20240123011445)
			my $webdriver = $firefox->script('return navigator.webdriver');
			ok($webdriver, "navigator.webdriver returns true:" . (defined $webdriver ? $webdriver : q[undef]));
		}
	}
	ok(!defined $firefox->child_error(), "Firefox does not have a value for child_error");
	ok($firefox->alive(), "Firefox is still alive");
	ok(not($firefox->script('window.open("about:blank", "_blank");')), "Opening new window to about:blank via 'window.open' script");
	ok($firefox->close_current_window_handle(), "Closed new tab/window");
	SKIP: {
		if ($major_version < 55) {
			skip("Deleting and re-creating sessions can hang firefox for old versions", 1);
		}
		ok($firefox->delete_session()->new_session(), "\$firefox->delete_session()->new_session() has cleared the old session and created a new session");
	}
	my $child_error = $firefox->quit();
	if ($child_error != 0) {
		diag("Firefox exited with a \$? of $child_error");
	}
	ok($child_error =~ /^\d+$/, "Firefox has closed with an integer exit status of " . $child_error);
	if ($major_version < 50) {
		$correct_exit_status = $child_error;
	}
	ok($firefox->child_error() == $child_error, "Firefox returns $child_error for the child error, matching the return value of quit():$child_error:" . $firefox->child_error());
	ok(!$firefox->alive(), "Firefox is not still alive");
}
if ((!defined $major_version) || ($major_version < 40)) {
	$profile->set_value('security.tls.version.max', 3); 
}
$profile->set_value('browser.newtabpage.activity-stream.feeds.favicon', 'true'); 
$profile->set_value('browser.shell.shortcutFavicons', 'true'); 
$profile->set_value('browser.newtabpage.enabled', 'true'); 
$profile->set_value('browser.pagethumbnails.capturing_disabled', 'false', 0); 
$profile->set_value('startup.homepage_welcome_url', 'false', 0); 

my $metacpan_bookmark_icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAGbElEQVRYhcWWTWwV1xXHf+fcO8/PNjYFTFH5MIJNJJQIDE0LwU4faRaojUQlJHaITbtglVUWjbpwF0gsk32zqCxFFUiVsijpJvIjDkppagG1RMTG1FZJRWMixd+emXtPF2/med7DJptKudLTzJt77v...
my $metacpan_bookmark_icon_url = 'fake-favicon-uri:https://metacpan.org/pod/Firefox::Marionette';
my $metacpan_uri = 'https://metacpan.org/';

SKIP: {
	if (($ENV{FIREFOX_NO_RECONNECT})) {
		if ($ENV{FIREFOX_HOST}) {
			skip("$ENV{FIREFOX_HOST} is not supported for reconnecting yet", 8);
		} else {
			skip("$^O is not supported for reconnecting yet", 8);
		}
	} elsif (!$mozilla_pid_support) {
		skip("No pid support for this version of firefox", 8);
	} elsif (!$ENV{RELEASE_TESTING}) {
		skip("No survive testing except for RELEASE_TESTING", 8);
	}
	diag("Starting new firefox for testing reconnecting");
	($skip_message, $firefox) = start_firefox(0, debug => 'timestamp,cookie:2', survive => 1);
	if (!$skip_message) {
		$at_least_one_success = 1;
	}
	if ($skip_message) {
		skip($skip_message, 8);
	}
	ok($firefox, "Firefox has started in Marionette mode with as survivable");
	my $capabilities = $firefox->capabilities();
	ok((ref $capabilities) eq 'Firefox::Marionette::Capabilities', "\$firefox->capabilities() returns a Firefox::Marionette::Capabilities object");
	my $firefox_pid = $capabilities->moz_process_id();
	ok($firefox_pid, "Firefox process has a process id of $firefox_pid");
	if (!$ENV{FIREFOX_HOST}) {
		ok(process_alive($firefox_pid), "Can contact firefox process ($firefox_pid)");
	}
	$firefox = undef;
	if (!$ENV{FIREFOX_HOST}) {
		ok(process_alive($firefox_pid), "Can contact firefox process ($firefox_pid)");
	}
	($skip_message, $firefox) = start_firefox(0, debug => 1, reconnect => 1);
	ok($firefox, "Firefox has reconnected in Marionette mode");
	$capabilities = $firefox->capabilities();
	ok($firefox_pid == $capabilities->moz_process_id(), "Firefox has the same process id");
	$firefox = undef;
	if (!$ENV{FIREFOX_HOST}) {
		ok(!process_alive($firefox_pid), "Cannot contact firefox process ($firefox_pid)");
	}
	if ($ENV{FIREFOX_HOST}) {
		if ($ENV{FIREFOX_BINARY}) {
			skip("No profile testing when the FIREFOX_BINARY override is used", 6);
		}
		if (!$ENV{RELEASE_TESTING}) {
			skip("No profile testing except for RELEASE_TESTING", 6);
		}
		if (($ENV{WATERFOX}) || ($ENV{WATERFOX_VIA_FIREFOX})) {
			skip("No profile testing when any WATERFOX override is used", 6);
		}
		if ($ENV{FIREFOX_DEVELOPER}) {
			skip("No profile testing when the FIREFOX_DEVELOPER override is used", 6);
		}
		if ($ENV{FIREFOX_NIGHTLY}) {
			skip("No profile testing when the FIREFOX_NIGHTLY override is used", 6);
		}
		my $name = 'throw';
		($skip_message, $firefox) = start_firefox(0, debug => 1, profile_name => $name );
		if (!$skip_message) {
			$at_least_one_success = 1;
		}
		if ($skip_message) {
			skip($skip_message, 6);
		}
		ok($firefox, "Firefox has started in Marionette mode with a profile_name");
		my $capabilities = $firefox->capabilities();
		ok((ref $capabilities) eq 'Firefox::Marionette::Capabilities', "\$firefox->capabilities() returns a Firefox::Marionette::Capabilities object");
		my $firefox_pid = $capabilities->moz_process_id();
		ok($firefox_pid, "Firefox process has a process id of $firefox_pid when using a profile_name");
		my $child_error = $firefox->quit();
		if ($child_error != 0) {
			diag("Firefox exited with a \$? of $child_error");
		}
		ok($child_error =~ /^\d+$/, "Firefox has closed with an integer exit status of " . $child_error);
		if ($major_version < 50) {
			$correct_exit_status = $child_error;
		}
		ok($firefox->child_error() == $child_error, "Firefox returns $child_error for the child error, matching the return value of quit():$child_error:" . $firefox->child_error());
		ok(!$firefox->alive(), "Firefox is not still alive");
	} else {
		if ($ENV{FIREFOX_BINARY}) {
			skip("No profile testing when the FIREFOX_BINARY override is used", 6);
		}
		if (!$ENV{RELEASE_TESTING}) {
			skip("No profile testing except for RELEASE_TESTING", 6);
		}
		if (($ENV{WATERFOX}) || ($ENV{WATERFOX_VIA_FIREFOX})) {
			skip("No profile testing when any WATERFOX override is used", 6);
		}
		if ($ENV{FIREFOX_DEVELOPER}) {
			skip("No profile testing when the FIREFOX_DEVELOPER override is used", 6);
		}
		if ($ENV{FIREFOX_NIGHTLY}) {
			skip("No profile testing when the FIREFOX_NIGHTLY override is used", 6);
		}
		my $found;
		my @names = Firefox::Marionette::Profile->names();
		foreach my $name (@names) {
			if ($name eq 'throw') {
				$found = 1;
			}
		}
		if (!$found) {
			skip("No profile testing when throw profile doesn't exist", 6);
		}
		my $name = 'throw';
		($skip_message, $firefox) = start_firefox(0, debug => 1, har => 1, survive => 1, profile_name => $name );
		if (!$skip_message) {
			$at_least_one_success = 1;
		}
		if ($skip_message) {
			skip($skip_message, 8);
		}
		ok($firefox, "Firefox has started in Marionette mode with as survivable with a profile_name and har");
		my $capabilities = $firefox->capabilities();
		ok((ref $capabilities) eq 'Firefox::Marionette::Capabilities', "\$firefox->capabilities() returns a Firefox::Marionette::Capabilities object");
		my $firefox_pid = $capabilities->moz_process_id();
		ok($firefox_pid, "Firefox process has a process id of $firefox_pid when using a profile_name");
		ok(process_alive($firefox_pid), "Can contact firefox process ($firefox_pid) when using a profile_name");
		$firefox = undef;
		ok(process_alive($firefox_pid), "Can contact firefox process ($firefox_pid) when using a profile_name");
		($skip_message, $firefox) = start_firefox(0, debug => 1, reconnect => 1, profile_name => $name);
		ok($firefox, "Firefox has reconnected in Marionette mode when using a profile_name");
		ok($firefox_pid == $capabilities->moz_process_id(), "Firefox has the same process id when using a profile_name");
		$firefox = undef;
		ok(!process_alive($firefox_pid), "Cannot contact firefox process ($firefox_pid)");
	}
}

if ($^O eq 'MSWin32') {
} elsif ($ENV{RELEASE_TESTING}) {
	eval {
		$ca_cert_handle = File::Temp->new( TEMPLATE => File::Spec->catfile( File::Spec->tmpdir(), 'firefox_test_ca_cert_XXXXXXXXXXX')) or Firefox::Marionette::Exception->throw( "Failed to open temporary file for writing:$!");
		fcntl $ca_cert_handle, Fcntl::F_SETFD(), 0 or Carp::croak("Can't clear close-on-exec flag on temporary file:$!");
		$ca_private_key_handle = File::Temp->new( TEMPLATE => File::Spec->catfile( File::Spec->tmpdir(), 'firefox_test_ca_private_XXXXXXXXXXX')) or Firefox::Marionette::Exception->throw( "Failed to open temporary file for writing:$!");
		system {'openssl'} 'openssl', 'genrsa', '-out' => $ca_private_key_handle->filename(), 4096 and Carp::croak("Failed to generate a private key:$!");
		my $ca_config_handle = File::Temp->new( TEMPLATE => File::Spec->catfile( File::Spec->tmpdir(), 'firefox_test_ca_config_XXXXXXXXXXX')) or Firefox::Marionette::Exception->throw( "Failed to open temporary file for writing:$!");
		$ca_config_handle->print(<<"_CONFIG_");
[ req ]
distinguished_name     = req_distinguished_name
attributes             = req_attributes
prompt                 = no

[ req_distinguished_name ]
C                      = AU
ST                     = Victoria
L                      = Melbourne
O                      = David Dick
OU                     = CPAN
CN                     = Firefox::Marionette Root CA
emailAddress           = ddick\@cpan.org

[ req_attributes ]
_CONFIG_
		seek $ca_config_handle, 0, 0 or Carp::croak("Failed to seek to start of temporary file:$!");
		fcntl $ca_config_handle, Fcntl::F_SETFD(), 0 or Carp::croak("Can't clear close-on-exec flag on temporary file:$!");
		system {'openssl'} 'openssl', 'req', '-new', '-x509',
			'-set_serial' => '1',
			'-config'     => $ca_config_handle->filename(),
			'-days'       => 10,
			'-key'        => $ca_private_key_handle->filename(),
			'-out'        => $ca_cert_handle->filename()
			and Carp::croak("Failed to generate a CA root certificate:$!");
		1;
	} or do {
		chomp $@;
		diag("Did not generate a CA root certificate:$@");
	};
}

SKIP: {
	diag("Starting new firefox for testing capabilities and accessing proxies");
	my $daemon = HTTP::Daemon->new(LocalAddr => 'localhost') || die "Failed to create HTTP::Daemon";
	my $proxyPort = URI->new($daemon->url())->port();
	my $securePort = empty_port();
	diag("Using proxy port TCP/$proxyPort");
	my $socksPort = empty_port();
	diag("Using SOCKS port TCP/$socksPort");
	my %proxy_parameters = (http => 'localhost:' . $proxyPort, https => 'localhost:' . $securePort, none => [ 'local.example.org' ], socks => 'localhost:' . $socksPort);
	my $ftpPort = empty_port();
	if ($binary =~ /waterfox/i) {
	} elsif ((defined $major_version) && ($major_version < 90)) {
		diag("Using FTP port TCP/$ftpPort");
		$proxy_parameters{ftp} = 'localhost:' . $ftpPort;
	}
	my $proxy = Firefox::Marionette::Proxy->new(%proxy_parameters);

t/01-marionette.t  view on Meta::CPAN

		}
	}
	SKIP: {
		local $TODO = "Not entirely stable in firefox";
		my $full_screen;
		local $SIG{ALRM} = sub { die "alarm during full screen\n" };
		alarm 15;
		eval {
			$full_screen = $firefox->full_screen();
		} or do {
			diag("Crashed during \$firefox->full_screen:$@");
		};
		alarm 0;
		ok($full_screen, "\$firefox->full_screen()");
		my $minimise;
		local $SIG{ALRM} = sub { die "alarm during minimise\n" };
		alarm 15;
		eval {
			$minimise = $firefox->minimise();
		} or do {
			diag("Crashed during \$firefox->minimise:$@");
		};
		alarm 0;
		ok($minimise, "\$firefox->minimise()");
		local $SIG{ALRM} = sub { die "alarm during maximise\n" };
		alarm 15;
		eval {
			$maximise = $firefox->maximise();
		} or do {
			diag("Crashed during \$firefox->maximise:$@");
		};
		alarm 0;
		ok($maximise, "\$firefox->maximise()");
	}
	if ($ENV{FIREFOX_HOST}) {
		SKIP: {
			skip("Not testing dead firefox processes with ssh", 2);	
		}
		TODO: {
			local $TODO = $correct_exit_status == 0 ? q[] : $capabilities->browser_version() . " is not exiting cleanly";
			ok($firefox->quit() == $correct_exit_status, "Firefox has closed with an exit status of $correct_exit_status:" . $firefox->child_error());
		}
	} elsif (($^O eq 'MSWin32') || (!grep /^moz_process_id$/, $capabilities->enumerate())) {
		SKIP: {
			skip("Not testing dead firefox processes for win32/early firefox versions", 2);	
		}
		TODO: {
			local $TODO = $correct_exit_status == 0 ? q[] : $capabilities->browser_version() . " is not exiting cleanly";
			ok($firefox->quit() == $correct_exit_status, "Firefox has closed with an exit status of $correct_exit_status:" . $firefox->child_error());
		}
	} elsif ($^O eq 'cygwin') {
		SKIP: {
			skip("Not testing dead firefox processes for cygwin", 2);	
		}
		TODO: {
			local $TODO = $correct_exit_status == 0 ? q[] : $capabilities->browser_version() . " is not exiting cleanly";
			ok($firefox->quit() == $correct_exit_status, "Firefox has closed with an exit status of $correct_exit_status:" . $firefox->child_error());
		}
	} else {
		my $xvfb_pid = $firefox->xvfb_pid();
		while($firefox->alive()) {
			diag("Killing PID " . $capabilities->moz_process_id() . " with a signal " . $signals_by_name{TERM});
			sleep 1; 
			kill $signals_by_name{TERM}, $capabilities->moz_process_id();
			sleep 1; 
		}
		eval { $firefox->go('https://metacpan.org') };
		chomp $@;
		ok($@ =~ /Firefox[ ]killed[ ]by[ ]a[ ]TERM[ ]signal/smx, "Exception is thrown when a command is issued to a dead firefox process:$@");
		eval { $firefox->go('https://metacpan.org') };
		chomp $@;
		ok($@ =~ /Firefox[ ]killed[ ]by[ ]a[ ]TERM[ ]signal/smx, "Consistent exception is thrown when a command is issued to a dead firefox process:$@");
		ok($firefox->quit() == $signals_by_name{TERM}, "Firefox has been killed by a signal with value of $signals_by_name{TERM}:" . $firefox->child_error() . ":" . $firefox->error_message());
		diag("Error Message was " . $firefox->error_message());
		if (defined $xvfb_pid) {
			ok((!(kill 0, $xvfb_pid)) && ($! == POSIX::ESRCH()), "Xvfb process $xvfb_pid has been cleaned up:$!");
		} else {
			ok(1, "No Xvfb process exists");
		}
	}
}

SKIP: {
	diag("Starting new firefox for testing visibility and TLS proxy servers");
	my $proxyPort = empty_port();
	my $proxy_host = 'localhost:' . $proxyPort;
	if ($major_version == 45) {
		skip("Skipping b/c of proxy setCharPref exceptions", 1);
	}
	if ($major_version == 38) {
		skip("Skipping b/c proxy must be undefined", 1);
	}
	if ($major_version >= 135) {
		skip("Skipping b/c proxy seems to cause hangs", 1);
	}
	($skip_message, $firefox) = start_firefox(1, visible => 1, width => 800, height => 600,capabilities => Firefox::Marionette::Capabilities->new(moz_headless => 0, proxy => Firefox::Marionette::Proxy->new(tls => $proxy_host)));
	if (!$skip_message) {
		$at_least_one_success = 1;
	}
	if ($skip_message) {
		skip($skip_message, 451);
	}
	ok($firefox, "Firefox has started in Marionette mode with visible set to 1");
	my $capabilities = $firefox->capabilities();
	ok((ref $capabilities) eq 'Firefox::Marionette::Capabilities', "\$firefox->capabilities() returns a Firefox::Marionette::Capabilities object");
	SKIP: {
		if (!$capabilities->proxy()) {
			diag("\$capabilities->proxy is not supported for " . $capabilities->browser_version());
			skip("\$capabilities->proxy is not supported for " . $capabilities->browser_version(), 4);
		}
		ok($capabilities->proxy()->type() eq 'pac', "\$capabilities->proxy()->type() is 'pac'");
		ok($capabilities->proxy()->pac() =~ /^data:text\/plain,function(?:[ ]|%20)FindProxyForURL[(][)](?:[{]|%7B)return(?:[ ]|%20)(?:"|%22)HTTPS(?:[ ]|%20)localhost:$proxyPort(?:"|%22)(?:[}]|%7D)$/smx, qq[\$capabilities->proxy()->pac() is 'data:text/plain...
	}
	if ($major_version < 52) {
		diag("Not attempting to resize for Firefox $major_version");
	} elsif ($maximise) {
		local $TODO = q[];
		my $count = 0;
		my $resize_works;
		foreach my $display ($firefox->displays()) {
			$count += 1;



( run in 1.779 second using v1.01-cache-2.11-cpan-364913b4093 )