Mozilla-Mechanize-GUITester

 view release on metacpan or  search on metacpan

lib/Mozilla/Mechanize/GUITester.pm  view on Meta::CPAN

  # click mouse at the element position + (1, 1)
  $mech->x_click($elem, 1, 1);

  # play with the mouse relative to the element position
  $mech->x_mouse_down($elem, 2, 2);
  $mech->x_mouse_move($elem, 4, 4);
  $mech->x_mouse_up($elem, 4, 4);

  # send keystrokes to the application
  $mech->x_send_keys('{DEL}');

  # press and release left CTRL button. You can click in the middle.
  $mech->x_press_key('LCT');
  $mech->x_release_key('LCT');

  # run some javascript code and print its result
  print $mech->run_js('return "js: " + 2');

  # find out element style using its id
  print $mech->get_element_style_by_id('the_elem_id', 'background-color');

  # are there any javascript errors?
  print Dumper($mech->console_messages);

  # find out HTTP response status (works only for HTTP protocol)
  print $mech->status;

  # change some text box by sending keypresses - fires all JS events
  my $input = $mech->get_html_element_by_id("tbox", "Input");
  $mech->x_change_text($input, "Hi");

=head1 DESCRIPTION

This module enhances Mozilla::Mechanize with convenience functions allowing
testing of DHTML/JavaScript rich pages.

It uses X11::GUITest to emulate mouse clicking, dragging and moving over
elements in DOM tree.

It also allows running of arbitrary javascript code in the page context and
getting back the results.

C<MMG_TIMEOUT> environment variable can be used to adjust timeout of X events
(given in milliseconds).

=head1 CONSTRUCTION

=head2 Mozilla::Mechanize::GUITester->new(%options);

This constructor delegates to Mozilla::Mechanize::new function. See
Mozilla::Mechanize manual for its description.

=cut
sub new {
	my $home = $ENV{HOME};
	my $td = tempdir("/tmp/mozilla_guitester_XXXXXX", CLEANUP => 1);
	local $ENV{HOME} = $td;
	local $ENV{MOZ_NO_REMOTE} = 1;
	my $self = shift()->SUPER::new(@_);
	$self->{_home} = $td;
	$self->{_popups} = {};
	$self->{_alerts} = '';
	$self->{_console_messages} = [];

	$self->{_window_id} = $self->agent->{window}->window->XWINDOW;
	confess("# Unable to find window id") unless $self->window_id;

	Mozilla::PromptService::Register({ DEFAULT => sub {
		my $name = shift;
		$self->{_popups}->{$name} = [ @_ ];
		$self->{_alerts} .= $_[2] . "\n";
	} , Confirm => sub { return $self->{_confirm_result} }
	, Prompt => sub { return $self->{_prompt_result}; } });
	$self->{_reqs_count} = 0;
	Mozilla::ObserverService::Register({
		'http-on-examine-response' => sub {
			$self->_N('http-on-examine-response');
			my $channel = shift;
			$self->{_response_status} = $channel->responseStatus;
			$self->{_reqs_count}-- if $self->{_reqs_count} > 0;
		}, "http-on-modify-request" => sub {
			$self->_N('http-on-modify-request');
			$self->{_reqs_count}++;
		}, "http-on-examine-cached-response" => sub {
			$self->_N('http-on-examine-cached-response');
			$self->{_reqs_count}-- if $self->{_reqs_count} > 0;
 		}
	});
	$self->{_console_handle} = Mozilla::ConsoleService::Register(sub {
		my $msg = shift;
		push @{ $self->console_messages }, $msg if $msg;
	});
	return $self;
}

sub _countdown_requests {
	my ($self) = @_;
	$self->_N(join("", Carp::longmess()) . "_countdown_requests");
	$self->_wait_for_gtk;
	my $n = 1;
	while ($self->{_reqs_count} > 0) {
		$self->_N("iteration $n");
		my $rq = $self->{_reqs_count};
		$self->_wait_for_gtk;

		next if $rq != $self->{_reqs_count};
		if (($n++ % 50) == 0) {
			$self->_N("forcing reqs count");
			$self->{_reqs_count}--;
		}
	}
	$self->_N("_countdown_requests finish");
}

sub _wait_while_busy {
	my $self = shift;
	$self->_countdown_requests; 
	$self->{$_} = undef for qw(forms cur_form links images);
	return 1;
}
 
=head1 ACCESSORS

=head2 $mech->status

Returns last response status using Mozilla::ObserverService and
nsIHTTPChannel:responseStatus function.

Note that it works only for HTTP requests.

=cut
sub status { return shift()->{_response_status}; }

=head2 $mech->last_alert

Returns last alert contents intercepted through Mozilla::PromptService.

It is useful for communication from javascript.

=cut
sub last_alert { return shift()->{_popups}->{Alert}->[2]; }

=head2 $mech->console_messages

Returns arrayref of all console messages (e.g. javascript errors) aggregated
so far.

See Mozilla nsIConsoleService documentation for more details.

=cut
sub console_messages { return shift()->{_console_messages}; }

=head2 $mech->window_id

Returns window id of guitester window.

=cut
sub window_id { return shift()->{_window_id}; }

=head1 METHODS

=head2 $mech->x_resize_window($width, $height)

Resizes window to $width, $height. Dies if the screen is too small for it.

=cut
sub x_resize_window {
	my ($self, $width, $height) = @_;
	my ($x, $y) = GetScreenRes();
	die "Screen width is too small: $x < $width" if ($x < $width);
	die "Screen height is too small: $y < $height" if ($y < $height);
	ResizeWindow($self->window_id, $width, $height);
}

=head2 $mech->pull_alerts

Pulls all alerts aggregated so far and resets alerts stash. Useful for JS
debugging.

=cut
sub pull_alerts {
	my $self = shift;
	my $res = $self->{_alerts};
	$self->{_alerts} = '';
	return $res;
}

=head2 $mech->set_confirm_result($res)

Future C<confirm> JavaScript calls will return C<$res> as a result.

=cut
sub set_confirm_result {
	my ($self, $res) = @_;
	$self->{_confirm_result} = $res;
}

=head2 $mech->set_prompt_result($res)

Future prompt JavaScript calls will return C<$res> as a result.



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