SlideShare a Scribd company logo
High-level web testing Peter Sergeant Contractor @ NET-A-PORTER
 
 
# $mech is a WWW::Mechanize subclass object $mech ->get( '/Fulfilment/Putaway?process_group=844284' ); print   Dumper   $mech ->as_data(); # Page contents as data $VAR1  = { 'metadata'  => { 'delivery_number'   =>  '615019' , 'process_group_id'   =>  '844284' , 'page_type'   =>  'Surplus' , 'Designer'   =>  'Rows' , 'Description'   =>  'New Description' , 'Colour'   =>  'Black' , 'Sales Channel'   =>  'MRPORTER.COM' }, 'item_list'  => [ { 'Size'  =>  'None/Unknown' , 'SKU'  =>  '2106034-001' }, { 'Size'  =>  'None/Unknown' , 'SKU'  =>  '2106034-005' } ] };
'Fulfilment/PackingException/ViewContainer'  => { auto_match  =>  qr!^/Fulfilment/PackingException/ViewContainer\?container_id=M\w+ $! , specification  => { orphaned_items  => { location  =>  'id("orphaned_items")' , transform  =>  'parse_table' , optional  =>  1 , }, shipment_items  => { location  =>  'id("shipment_items")' , transform  =>  'parse_table' , optional  =>  1 , }, cancelled_items  => { location  =>  'id("cancelled_items")' , transform  =>  'parse_table' , optional  =>  1 , }, } },
'Fulfilment/Packing/EmptyTote'  => { auto_match  => qr!^/Fulfilment/Packing/EmptyTote!, specification  => { totes  => { location  =>  'id("totes")' , transform  =>  'parse_simple_list' , }, }, },
=head2  parse_simple_list Return a simplified text representation of the li elements under a node. =cut sub  _xclient_parse_simple_list  { my  ( $self ,  $list_node ) =  @_ ; # Find the child elements  my   @li_elements  =  $list_node ->find_xpath( 'li' )->get_nodelist(); # Render them as text my   @simplified  =  map  { $self ->_xclient_trim_cell( $_ ->as_text) }  @li_elements ; # And give them back... return   \@simplified ; }
# Send the shipment ID $mech ->submit_form_ok({ with_fields  => { shipment_nr =  $shipment_id  } },  "Shipment ID submitted" );
# Check we're in the right place, and then submit the form unless  (  $mech ->uri->path  eq   '/Fulfilment/Selection'  ) { die   "Expecting to be on /Fulfilment/Selection, actually: "  . $mech ->uri->path } # Send the shipment ID $mech ->submit_form_ok({ with_fields  => { shipment_nr =  $shipment_id  } },  "Shipment ID submitted" );
# Check we're in the right place, and then submit the form unless  (  $mech ->uri->path  eq   '/Fulfilment/Selection'  ) { die   "Expecting to be on /Fulfilment/Selection, actually: "  . $mech ->uri->path } # Send the shipment ID $mech ->submit_form_ok({ with_fields  => { shipment_nr =  $shipment_id  } },  "Shipment ID submitted" ); # Check we didn't get any logical errors if  (  $mech ->as_data->error_message ) { die   "HTTP request passed, but the application complained: "  . $mech ->as_data->error_message; }
__PACKAGE__->create_fetch_method( method_name  =>  'flow_mech__fulfilment__packingexception' , page_description  =>  'packing Exception Page' , page_url  =>  '/Fulfilment/PackingException' ); __PACKAGE__->create_form_method( method_name  =>  'flow_mech__fulfilment__packingexception_comment' , form_name  =>  'add_comments' , form_description  =>  'add comment' , assert_location  => qr!^/Fulfilment/Packing/CheckShipmentException!, transform_fields  =>   sub   {  return  {  note_text  =>  $_ [ 1 ] } }, ); #------------------------------------------------------------------------------- $framework ->flow_mech__fulfilment__packingexception ->flow_mech__fulfilment__packingexception_comment( "The quick brown fox ran over the lazy sheep dog" ); #------------------------------------------------------------------------------- #  ->flow_mech__fulfilment__packingexception() #  Retrieving the packing Exception Page #  URL /Fulfilment/PackingException retrieved successfully via HTTP #  No status message shown #  Retrieved the packing Exception Page #  ->flow_mech__fulfilment__packingexception_comment( "Comment 1:70236" ) #  URL [/Fulfilment/Packing/CheckShipmentException] matched assertion #  Searching for the add comment form #  Submitting add comment form #  URL /Fulfilment/Packing/CheckShipmentException?shipment_id=1630767 retrieved successfully via HTTP #  No status message shown
# Look for our purchase order $flow ->flow_mech__goodsin__stockin ->flow_mech__goodsin__stockin_search({ purchase_order_number  =>  $purchase_order_id }); # Did we find it? is( $flow ->mech->as_data->{ 'products' }->[ 0 ]->{ 'PID' }, $product_id , "Found our product from the purchase order search" ); # Check the packing slip $flow ->flow_mech__goodsin__stockin_packingslip(  $flow ->stock_order->id ) # Is it sensible? is( $flow ->mech->as_data->{ 'product_data' }->{ 'Purchase Order' }->{ 'value' }, $purchase_order ->purchase_order_number, "Purchase order matched from Stock Order page" );
sub  create_form_method  { my  (  $class ,  %args  ) =  @_ ; # This is a good place to check a user is using it correctly... $class ->_auto_methods_check_params( \%args , { required  => [ qw/ method_name form_name form_description assert_location / ], optional  => [ 'form_button' ,  'transform_fields' ], }); $class ->meta->add_method( $args { 'method_name' } =>   sub   { my  (  $self ,  @user_options  ) =  @_ ; $self ->show_method_name(  $args { 'method_name' },  @user_options  ); $self ->assert_location(  $args { 'assert_location' } ) if   defined   $args { 'assert_location' }; my   $transformed_fields  =  $args { 'transform_fields' } ? $args { 'transform_fields' }->(  $self ,  @user_options  ) : {}; $self ->indent_note( "Searching for the  $args {'form_description'} form" ); my   $name  =  ref ( $args { 'form_name' })  eq   'CODE'  ? $args { 'form_name' }->(  $self ,  @user_options  ) : $args { 'form_name' }; my   $form  =  $self ->mech->form_name(  $name  ); unless  (  $form  ) { croak   "Couldn't find a form with name  $args {'form_name'}" ; } $self ->mech->set_fields(  %$transformed_fields  ); my   $button  =  ref ( $args { 'form_button' })  eq   'CODE'  ? $args { 'form_button' }->(  $self ,  @user_options  ) : $args { 'form_button' }; $self ->indent_note( "Submitting  $args {'form_description'} form" ); $self ->mech->submit_form( fields  =>  $transformed_fields , $button  ? (  button  =>  $button  ) : () ); $self ->note_status; return   $self ; } ); }
Come and work at Net-A-Porter We’re hiring It’s a lot of fun Nice offices

More Related Content

What's hot (19)

PPTX
Views notwithstanding
Srikanth Bangalore
 
PDF
Shortcodes In-Depth
Micah Wood
 
PPTX
Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2
Atwix
 
PDF
WordPress-Powered Portfolios
Tyler Sticka
 
PDF
introduction to Django in five slides
Dan Chudnov
 
PPT
What's new in Rails 2?
brynary
 
PDF
VoCamp Seoul2009 Sparql
kwangsub kim
 
ODP
Writing Maintainable Perl
tinypigdotcom
 
PDF
Dealing With Legacy PHP Applications
Viget Labs
 
PDF
PHP「参照渡しできるよ」(君の考えている参照渡しと同じとは言ってない)
Kana Natsuno
 
PDF
Routing System In Symfony 1.2
Alex Demchenko
 
ODP
State Machines to State of the Art
Rowan Merewood
 
PDF
WordPress REST API: Expert Advice & Practical Use Cases
Pantheon
 
PPT
PHP
webhostingguy
 
PDF
Storytelling By Numbers
Michael King
 
PDF
The Critical Need for Encrypted Email and File Transfer Solutions
Osterman Research, Inc.
 
Views notwithstanding
Srikanth Bangalore
 
Shortcodes In-Depth
Micah Wood
 
Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2
Atwix
 
WordPress-Powered Portfolios
Tyler Sticka
 
introduction to Django in five slides
Dan Chudnov
 
What's new in Rails 2?
brynary
 
VoCamp Seoul2009 Sparql
kwangsub kim
 
Writing Maintainable Perl
tinypigdotcom
 
Dealing With Legacy PHP Applications
Viget Labs
 
PHP「参照渡しできるよ」(君の考えている参照渡しと同じとは言ってない)
Kana Natsuno
 
Routing System In Symfony 1.2
Alex Demchenko
 
State Machines to State of the Art
Rowan Merewood
 
WordPress REST API: Expert Advice & Practical Use Cases
Pantheon
 
Storytelling By Numbers
Michael King
 
The Critical Need for Encrypted Email and File Transfer Solutions
Osterman Research, Inc.
 

Viewers also liked (8)

ODP
Avoiding common pitfalls of datetime from a webapp's perspective
indradhanush92
 
PDF
A music-sharing model of crowdsourcing in museums by ADOMultimedia
Stefania Zardini Lacedelli
 
PDF
Our local state, my, my - Understanding Perl variables
xSawyer
 
PPTX
A Wikipedian-in-Residence at the British Museum
Matthew Cock
 
PDF
Your first website in under a minute with Dancer
xSawyer
 
PDF
Why Twitter Is All the Rage: A Data Miner's Perspective
Matthew Russell
 
PDF
Exploring slides
akaptur
 
PDF
Wroc.py #32: Microservices in flask
Krzysztof Żuraw
 
Avoiding common pitfalls of datetime from a webapp's perspective
indradhanush92
 
A music-sharing model of crowdsourcing in museums by ADOMultimedia
Stefania Zardini Lacedelli
 
Our local state, my, my - Understanding Perl variables
xSawyer
 
A Wikipedian-in-Residence at the British Museum
Matthew Cock
 
Your first website in under a minute with Dancer
xSawyer
 
Why Twitter Is All the Rage: A Data Miner's Perspective
Matthew Russell
 
Exploring slides
akaptur
 
Wroc.py #32: Microservices in flask
Krzysztof Żuraw
 
Ad

Similar to High-level Web Testing (10)

PPT
Nine Ways to Use Network-Side Scripting
Lori MacVittie
 
ODP
Exploiting the newer perl to improve your plugins
Marian Marinov
 
ODP
Architecting Web Services
Lorna Mitchell
 
ODP
Mechanize at the Ruby Drink-up of Sophia, November 2011
rivierarb
 
PDF
Magic of Ruby
Gabriele Lana
 
PPT
Ontologizing Business Processes
Violeta Damjanovic-Behrendt
 
ODP
Schenker - DSL for quickly creating web applications in Perl
Jiro Nishiguchi
 
ODP
SCDJWS 3. WSDL
Francesco Ierna
 
PPT
Stop Making The Web Harder Than It Is; Real-world REST, HATEOAS, and Hypermed...
kiphampton
 
PDF
Orbitz and Spring Webflow Case Study
Mark Meeker
 
Nine Ways to Use Network-Side Scripting
Lori MacVittie
 
Exploiting the newer perl to improve your plugins
Marian Marinov
 
Architecting Web Services
Lorna Mitchell
 
Mechanize at the Ruby Drink-up of Sophia, November 2011
rivierarb
 
Magic of Ruby
Gabriele Lana
 
Ontologizing Business Processes
Violeta Damjanovic-Behrendt
 
Schenker - DSL for quickly creating web applications in Perl
Jiro Nishiguchi
 
SCDJWS 3. WSDL
Francesco Ierna
 
Stop Making The Web Harder Than It Is; Real-world REST, HATEOAS, and Hypermed...
kiphampton
 
Orbitz and Spring Webflow Case Study
Mark Meeker
 
Ad

Recently uploaded (20)

PPTX
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
PDF
Chris Elwell Woburn, MA - Passionate About IT Innovation
Chris Elwell Woburn, MA
 
PDF
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
PPTX
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
PDF
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
PPTX
OpenID AuthZEN - Analyst Briefing July 2025
David Brossard
 
PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PDF
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
PDF
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
PDF
Presentation - Vibe Coding The Future of Tech
yanuarsinggih1
 
PDF
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
PDF
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
PDF
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
PPTX
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
PDF
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
PDF
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
PDF
Using FME to Develop Self-Service CAD Applications for a Major UK Police Force
Safe Software
 
PDF
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
PPTX
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
PDF
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
Chris Elwell Woburn, MA - Passionate About IT Innovation
Chris Elwell Woburn, MA
 
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
OpenID AuthZEN - Analyst Briefing July 2025
David Brossard
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
Presentation - Vibe Coding The Future of Tech
yanuarsinggih1
 
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
Using FME to Develop Self-Service CAD Applications for a Major UK Police Force
Safe Software
 
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
Mastering Financial Management in Direct Selling
Epixel MLM Software
 

High-level Web Testing

  • 1. High-level web testing Peter Sergeant Contractor @ NET-A-PORTER
  • 2.  
  • 3.  
  • 4. # $mech is a WWW::Mechanize subclass object $mech ->get( '/Fulfilment/Putaway?process_group=844284' ); print Dumper $mech ->as_data(); # Page contents as data $VAR1 = { 'metadata' => { 'delivery_number' => '615019' , 'process_group_id' => '844284' , 'page_type' => 'Surplus' , 'Designer' => 'Rows' , 'Description' => 'New Description' , 'Colour' => 'Black' , 'Sales Channel' => 'MRPORTER.COM' }, 'item_list' => [ { 'Size' => 'None/Unknown' , 'SKU' => '2106034-001' }, { 'Size' => 'None/Unknown' , 'SKU' => '2106034-005' } ] };
  • 5. 'Fulfilment/PackingException/ViewContainer' => { auto_match => qr!^/Fulfilment/PackingException/ViewContainer\?container_id=M\w+ $! , specification => { orphaned_items => { location => 'id("orphaned_items")' , transform => 'parse_table' , optional => 1 , }, shipment_items => { location => 'id("shipment_items")' , transform => 'parse_table' , optional => 1 , }, cancelled_items => { location => 'id("cancelled_items")' , transform => 'parse_table' , optional => 1 , }, } },
  • 6. 'Fulfilment/Packing/EmptyTote' => { auto_match => qr!^/Fulfilment/Packing/EmptyTote!, specification => { totes => { location => 'id("totes")' , transform => 'parse_simple_list' , }, }, },
  • 7. =head2 parse_simple_list Return a simplified text representation of the li elements under a node. =cut sub _xclient_parse_simple_list { my ( $self , $list_node ) = @_ ; # Find the child elements my @li_elements = $list_node ->find_xpath( 'li' )->get_nodelist(); # Render them as text my @simplified = map { $self ->_xclient_trim_cell( $_ ->as_text) } @li_elements ; # And give them back... return \@simplified ; }
  • 8. # Send the shipment ID $mech ->submit_form_ok({ with_fields => { shipment_nr = $shipment_id } }, "Shipment ID submitted" );
  • 9. # Check we're in the right place, and then submit the form unless ( $mech ->uri->path eq '/Fulfilment/Selection' ) { die "Expecting to be on /Fulfilment/Selection, actually: " . $mech ->uri->path } # Send the shipment ID $mech ->submit_form_ok({ with_fields => { shipment_nr = $shipment_id } }, "Shipment ID submitted" );
  • 10. # Check we're in the right place, and then submit the form unless ( $mech ->uri->path eq '/Fulfilment/Selection' ) { die "Expecting to be on /Fulfilment/Selection, actually: " . $mech ->uri->path } # Send the shipment ID $mech ->submit_form_ok({ with_fields => { shipment_nr = $shipment_id } }, "Shipment ID submitted" ); # Check we didn't get any logical errors if ( $mech ->as_data->error_message ) { die "HTTP request passed, but the application complained: " . $mech ->as_data->error_message; }
  • 11. __PACKAGE__->create_fetch_method( method_name => 'flow_mech__fulfilment__packingexception' , page_description => 'packing Exception Page' , page_url => '/Fulfilment/PackingException' ); __PACKAGE__->create_form_method( method_name => 'flow_mech__fulfilment__packingexception_comment' , form_name => 'add_comments' , form_description => 'add comment' , assert_location => qr!^/Fulfilment/Packing/CheckShipmentException!, transform_fields => sub { return { note_text => $_ [ 1 ] } }, ); #------------------------------------------------------------------------------- $framework ->flow_mech__fulfilment__packingexception ->flow_mech__fulfilment__packingexception_comment( "The quick brown fox ran over the lazy sheep dog" ); #------------------------------------------------------------------------------- # ->flow_mech__fulfilment__packingexception() # Retrieving the packing Exception Page # URL /Fulfilment/PackingException retrieved successfully via HTTP # No status message shown # Retrieved the packing Exception Page # ->flow_mech__fulfilment__packingexception_comment( "Comment 1:70236" ) # URL [/Fulfilment/Packing/CheckShipmentException] matched assertion # Searching for the add comment form # Submitting add comment form # URL /Fulfilment/Packing/CheckShipmentException?shipment_id=1630767 retrieved successfully via HTTP # No status message shown
  • 12. # Look for our purchase order $flow ->flow_mech__goodsin__stockin ->flow_mech__goodsin__stockin_search({ purchase_order_number => $purchase_order_id }); # Did we find it? is( $flow ->mech->as_data->{ 'products' }->[ 0 ]->{ 'PID' }, $product_id , "Found our product from the purchase order search" ); # Check the packing slip $flow ->flow_mech__goodsin__stockin_packingslip( $flow ->stock_order->id ) # Is it sensible? is( $flow ->mech->as_data->{ 'product_data' }->{ 'Purchase Order' }->{ 'value' }, $purchase_order ->purchase_order_number, "Purchase order matched from Stock Order page" );
  • 13. sub create_form_method { my ( $class , %args ) = @_ ; # This is a good place to check a user is using it correctly... $class ->_auto_methods_check_params( \%args , { required => [ qw/ method_name form_name form_description assert_location / ], optional => [ 'form_button' , 'transform_fields' ], }); $class ->meta->add_method( $args { 'method_name' } => sub { my ( $self , @user_options ) = @_ ; $self ->show_method_name( $args { 'method_name' }, @user_options ); $self ->assert_location( $args { 'assert_location' } ) if defined $args { 'assert_location' }; my $transformed_fields = $args { 'transform_fields' } ? $args { 'transform_fields' }->( $self , @user_options ) : {}; $self ->indent_note( "Searching for the $args {'form_description'} form" ); my $name = ref ( $args { 'form_name' }) eq 'CODE' ? $args { 'form_name' }->( $self , @user_options ) : $args { 'form_name' }; my $form = $self ->mech->form_name( $name ); unless ( $form ) { croak "Couldn't find a form with name $args {'form_name'}" ; } $self ->mech->set_fields( %$transformed_fields ); my $button = ref ( $args { 'form_button' }) eq 'CODE' ? $args { 'form_button' }->( $self , @user_options ) : $args { 'form_button' }; $self ->indent_note( "Submitting $args {'form_description'} form" ); $self ->mech->submit_form( fields => $transformed_fields , $button ? ( button => $button ) : () ); $self ->note_status; return $self ; } ); }
  • 14. Come and work at Net-A-Porter We’re hiring It’s a lot of fun Nice offices