diff options
-rw-r--r-- | .cypress/.gitignore | 2 | ||||
-rw-r--r-- | .cypress/cypress.json | 4 | ||||
-rw-r--r-- | .cypress/cypress/integration/simple_spec.js | 16 | ||||
-rw-r--r-- | .travis.yml | 16 | ||||
-rwxr-xr-x | Vagrantfile | 2 | ||||
-rwxr-xr-x | bin/browser-tests | 129 | ||||
-rwxr-xr-x | bin/fixmystreet.com/fixture | 3 | ||||
-rw-r--r-- | cpanfile | 2 | ||||
-rw-r--r-- | cpanfile.snapshot | 50 | ||||
-rw-r--r-- | perllib/FixMyStreet/TestAppProve.pm | 90 |
10 files changed, 270 insertions, 44 deletions
diff --git a/.cypress/.gitignore b/.cypress/.gitignore new file mode 100644 index 000000000..f677bfcd7 --- /dev/null +++ b/.cypress/.gitignore @@ -0,0 +1,2 @@ +/cypress/videos +/cypress/screenshots diff --git a/.cypress/cypress.json b/.cypress/cypress.json new file mode 100644 index 000000000..dd3beceef --- /dev/null +++ b/.cypress/cypress.json @@ -0,0 +1,4 @@ +{ + "baseUrl": "http://localhost:3001", + "projectId": "y8vvs1" +} diff --git a/.cypress/cypress/integration/simple_spec.js b/.cypress/cypress/integration/simple_spec.js new file mode 100644 index 000000000..39000a022 --- /dev/null +++ b/.cypress/cypress/integration/simple_spec.js @@ -0,0 +1,16 @@ +describe('My First Test', function() { + it('Visits the home page', function() { + cy.visit('/'); + cy.contains('Go'); + cy.get('[name=pc]').type('BS10 5EE'); + cy.get('#postcodeForm').submit(); + cy.url().should('include', '/around'); + cy.get('#map_box').click(200, 200); + cy.get('[name=title]').type('Title'); + cy.get('[name=detail]').type('Detail'); + cy.get('[name=username]').type('user@example.org'); + cy.get('[name=password_sign_in]').type('password'); + cy.get('form').submit(); + cy.get('form').submit(); + }); +}); diff --git a/.travis.yml b/.travis.yml index 9641e2819..de3ec7b29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,9 +20,20 @@ perl: # Params::Classify breaks in 5.26, and Lingua::EN::Tagger needs upgrading # - "5.26" +cache: + directories: + - ~/.npm + - node_modules + +matrix: + include: + - perl: "5.22" + env: "CYPRESS=1" + env: global: - "S3_BUCKET=fixmystreet-bundle-cache" + - "CYPRESS=0" - secure: "llgWNfR/8pH0HjYpg+xhVxuqTaLC0GGUugfuINiUap7JxzjCZ2rlryxCXA4BCM8GUHa9wlYKhrKCSx+DM3EHRE0cLei7LNxAK1JSXLj3NihFQhqnq64tjDwGCSA4l7mlqErA7DK4Dpmh+hBp5f680akITAInM92CbwQZxLDYaCU=" - secure: "qW+WCgAF68itADxcbcq+nCnKx3vf3GX73HMfjfbkFFUsYmIR+ZaJ9yQMnGJwxIpCHTWLAeqyx4KO8N8T3GmNdKYzIMZemOzp4ED29YC31QOQeq1CwNp2hD5sq/o47d2BzXWwMYNvNXfxz1K6r2c6EMPUtu8X3B8ExZq1RzSFdXs=" @@ -38,10 +49,13 @@ addons: install: - .travis/install - 'if [ "$TRAVIS_PERL_VERSION" = "5.24" ]; then cpanm --quiet --notest Devel::Cover::Report::Codecov; fi' + - 'if [ "$CYPRESS" = "1" ]; then npm install cypress; fi' before_script: - commonlib/bin/gettext-makemo FixMyStreet - 'if [ "$TRAVIS_PERL_VERSION" = "5.24" ]; then export HARNESS_PERL_SWITCHES="-MDevel::Cover=+ignore,local/lib/perl5,commonlib,perllib/Catalyst/[^A],perllib/DBIx,perllib/Email,perllib/Template,^t"; fi' -script: "script/test --jobs 3 t" +script: + - 'if [ "$CYPRESS" = "0" ]; then script/test --jobs 3 t; fi' + - 'if [ "$CYPRESS" = "1" ]; then PATH=$(npm bin):$PATH bin/browser-tests run --record; fi' after_success: - .travis/after_script - 'if [ "$TRAVIS_PERL_VERSION" = "5.24" ]; then cover --report codecov; fi' diff --git a/Vagrantfile b/Vagrantfile index 536974693..b3647ad2b 100755 --- a/Vagrantfile +++ b/Vagrantfile @@ -23,6 +23,8 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # within the machine from a port on the host machine. In the example below, # accessing "localhost:8080" will access port 80 on the guest machine. config.vm.network :forwarded_port, guest: 3000, host: 3000 + # And 3001 for the Cypress test server + config.vm.network :forwarded_port, guest: 3001, host: 3001 config.vm.synced_folder ".", "/home/vagrant/fixmystreet", :owner => "vagrant", :group => "vagrant" diff --git a/bin/browser-tests b/bin/browser-tests new file mode 100755 index 000000000..0c56be918 --- /dev/null +++ b/bin/browser-tests @@ -0,0 +1,129 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +BEGIN { + use File::Basename qw(dirname); + use File::Spec; + my $d = dirname(File::Spec->rel2abs($0)); + require "$d/../setenv.pl"; +} + +use Getopt::Long ':config' => qw(pass_through auto_help); + +my $config_file = 'conf/general.yml-example'; +my $run_server; +my $run_cypress; +my $vagrant; +GetOptions( + 'config=s' => \$config_file, + 'server' => \$run_server, + 'cypress' => \$run_cypress, + 'vagrant' => \$vagrant, +); + +if ($vagrant) { + # Test inception + system('vagrant ssh -c "cd fixmystreet && bin/browser-tests --server 2>/dev/null" &'); + + require IO::Socket; + sub check_connection { + my $remote = IO::Socket::INET->new(Proto => "tcp", PeerAddr => "localhost", PeerPort => 3001) or return; + $remote->autoflush(1); + print $remote "GET / HTTP/1.0\r\n\r\n"; + while (<$remote>) { return 1; } + 0; + } + + local $| = 1; + print 'Waiting for test server'; + while (!check_connection()) { + print '.'; sleep 1; + } + print " done\n"; + system('bin/browser-tests', '--cypress', @ARGV); + system('vagrant', 'ssh', '-c', 'kill $(cat /tmp/cypress-server.pid)'); + exit; +} + +if (!$run_server && !$run_cypress) { + # If asked for neither, run both + $run_server = $run_cypress = 1; +} + +sub run { + my $cmd = shift @ARGV; + die "Must specify a cypress command\n" unless $cmd || !$run_cypress; + + if ($run_server) { + require FixMyStreet::TestAppProve; + require t::Mock::MapIt; + my $config_out = FixMyStreet::TestAppProve->get_config({ + config_file => $config_file, + # Want this to be like .com + ALLOWED_COBRANDS => [ 'fixmystreet' ], + MAPIT_URL => 'https://mapit.uk/', + }); + $ENV{FMS_OVERRIDE_CONFIG} = $config_out; + + # Set up, and load in some data + system('bin/make_css', 'fixmystreet.com'); + system('bin/fixmystreet.com/fixture', '--coords', '51.532851,-2.284277', '--name', 'Borsetshire', '--area-id', 2608, '--commit'); + } + + my $pid; + if ($run_server && $run_cypress) { + $pid = fork(); + die if not defined $pid; + } + + if (($run_cypress && !$run_server) || $pid) { + # Parent, run the test runner (then kill the child) + my $exit = system("cypress", $cmd, '--config', 'fixturesFolder=false,pluginsFile=false,supportFile=false,blacklistHosts=[gaze.mysociety.org,*.openstreetmap.org]', '--project', '.cypress', @ARGV); + kill 'TERM', $pid if $pid; + exit $exit >> 8; + } else { + # Child, run the server on port 3001 + local $ENV{FIXMYSTREET_APP_DEBUG} = 0; + require Plack::Runner; + my $runner = Plack::Runner->new; + $runner->parse_options('--listen', ':3001', '-s', 'Starman', '--env', 'deployment', '--pid', '/tmp/cypress-server.pid'); + $runner->run; + } +} + +run(); + + +__END__ + +=head1 NAME + +browser-tests - Run Cypress browser tests, set up for FixMyStreet. + +=head1 SYNOPSIS + +browser-tests [options] [cypress options] + + Options: + --config provide an override general.yml file + --server only run the test server, not cypress + --cypress only run cypress, not the test server + --vagrant run test server inside Vagrant, cypress outside + --help this help message + +Use browser-tests instead of running cypress directly, so that a clean +database is set up for Cypress to use, not affecting your normal dev database. +If you're running FixMyStreet in a VM, you can use this script to run the test +server in the VM and Cypress outside of it. + + $ browser-tests open # to run interactively + $ browser-tests run # run headlessly + $ browser-tests run --record --key # record and upload a run + $ browser-tests --vagrant run # run if you use Vagrant + +You need to have installed cypress already using npm, and it needs to be on +your PATH. + +=cut diff --git a/bin/fixmystreet.com/fixture b/bin/fixmystreet.com/fixture index fc04e531d..1aa85564f 100755 --- a/bin/fixmystreet.com/fixture +++ b/bin/fixmystreet.com/fixture @@ -110,6 +110,9 @@ foreach (FixMyStreet::Cobrand->available_cobrand_classes) { } } +my $cache_dir = path(FixMyStreet->config('UPLOAD_DIR')); +$cache_dir->mkpath; + my $user = $users{'user@example.org'}; my $num = 20; say "Created $num problems around '$location' in cobrand '$cobrand'"; @@ -130,7 +130,7 @@ recommends 'Linux::Inotify2' if $^O eq 'linux'; recommends 'Mac::FSEvents' if $^O eq 'darwin'; # Modules used by the test suite -requires 'Test::PostgreSQL'; +requires 'Test::PostgreSQL', '1.24'; requires 'CGI::Simple'; requires 'HTTP::Headers'; requires 'HTTP::Response'; diff --git a/cpanfile.snapshot b/cpanfile.snapshot index 83d855c98..b118d9c93 100644 --- a/cpanfile.snapshot +++ b/cpanfile.snapshot @@ -3039,6 +3039,14 @@ DISTRIBUTIONS ExtUtils::MakeMaker 0 Fcntl 0 POSIX 0 + perl 5.004 + File-Which-1.22 + pathname: P/PL/PLICEASE/File-Which-1.22.tar.gz + provides: + File::Which 1.22 + requirements: + ExtUtils::MakeMaker 0 + perl 5.006 Filesys-Notify-Simple-0.10 pathname: M/MI/MIYAGAWA/Filesys-Notify-Simple-0.10.tar.gz provides: @@ -3048,6 +3056,22 @@ DISTRIBUTIONS Test::More 0 Test::SharedFork 0 perl 5.008001 + Function-Parameters-2.001003 + pathname: M/MA/MAUKE/Function-Parameters-2.001003.tar.gz + provides: + Function::Parameters 2.001003 + Function::Parameters::Info 2.001003 + Function::Parameters::Param 2.001003 + requirements: + Carp 0 + ExtUtils::MakeMaker 0 + File::Find 0 + File::Spec 0 + Scalar::Util 0 + XSLoader 0 + perl 5.014000 + strict 0 + warnings 0 Geography-NationalGrid-1.6 pathname: P/PK/PKENT/Geography-NationalGrid-1.6.tar.gz provides: @@ -6164,18 +6188,25 @@ DISTRIBUTIONS Test::More 0 Test::Tester 0.107 perl 5.006 - Test-PostgreSQL-1.05 - pathname: T/TJ/TJC/Test-PostgreSQL-1.05.tar.gz + Test-PostgreSQL-1.24 + pathname: T/TJ/TJC/Test-PostgreSQL-1.24.tar.gz provides: - Test::PostgreSQL 1.05 + Test::PostgreSQL 1.24 requirements: - Class::Accessor::Lite 0 DBD::Pg 0 DBI 0 ExtUtils::MakeMaker 6.59 + File::Spec 0 + File::Which 0 + Function::Parameters 0 + Moo 0 + POSIX 0 Test::SharedFork 0.06 - Time::HiRes 0 - perl 5.008 + Tie::Hash::Method 0 + Try::Tiny 0 + Types::Standard 0 + User::pwent 0 + perl 5.014 Test-Requires-0.06 pathname: T/TO/TOKUHIROM/Test-Requires-0.06.tar.gz provides: @@ -6406,6 +6437,13 @@ DISTRIBUTIONS Scalar::Util 0 Sub::Quote 0 overload 0 + Tie-Hash-Method-0.02 + pathname: Y/YV/YVES/Tie-Hash-Method-0.02.tar.gz + provides: + Tie::Hash::Method 0.02 + requirements: + ExtUtils::MakeMaker 0 + Test::More 0 Tie-IxHash-1.23 pathname: C/CH/CHORNY/Tie-IxHash-1.23.tar.gz provides: diff --git a/perllib/FixMyStreet/TestAppProve.pm b/perllib/FixMyStreet/TestAppProve.pm index d549b0148..049f7da6c 100644 --- a/perllib/FixMyStreet/TestAppProve.pm +++ b/perllib/FixMyStreet/TestAppProve.pm @@ -33,6 +33,59 @@ END { cleanup(); } +my $pg; + +sub spin_up_database { + warn "Spinning up a Pg cluster/database...\n"; + $pg = Test::PostgreSQL->new(); + + warn sprintf "# Connected to %s\n", $pg->dsn; + + my $dbh = DBI->connect($pg->dsn); + + my $tmpwarn = $SIG{__WARN__}; + $SIG{__WARN__} = + sub { print STDERR @_ if $_[0] !~ m/NOTICE: CREATE TABLE/; }; + $dbh->do( path('db/schema.sql')->slurp ) or die $!; + $dbh->do( path('db/fixture.sql')->slurp ) or die $!; + $dbh->do( path('db/generate_secret.sql')->slurp ) or die $!; + $SIG{__WARN__} = $tmpwarn; + + return { + FMS_DB_PORT => $pg->port, + FMS_DB_NAME => 'test', + FMS_DB_USER => 'postgres', + FMS_DB_HOST => 'localhost', + FMS_DB_PASS => '', + }; +} + +sub get_config { + my $cls = shift; + my $extra_config = shift; + my $config_file = delete $extra_config->{config_file}; + my $db_config_file = delete $extra_config->{db_config_file}; + + my $config = YAML::Load( path($config_file)->slurp ); + if ($db_config_file) { + my $db_config = YAML::Load( path($db_config_file)->slurp ); + $config->{FMS_DB_PORT} = $db_config->{FMS_DB_PORT}; + $config->{FMS_DB_NAME} = $db_config->{FMS_DB_NAME}; + $config->{FMS_DB_USER} = $db_config->{FMS_DB_USER}; + $config->{FMS_DB_HOST} = $db_config->{FMS_DB_HOST}; + $config->{FMS_DB_PASS} = $db_config->{FMS_DB_PASS}; + } else { + my $new_db_config = $cls->spin_up_database(); + $config = { %$config, %$new_db_config }; + } + + $config = { %$config, %$extra_config }; + + my $config_out = "general-test-autogenerated.$$.yml"; + path("conf/$config_out")->spew( YAML::Dump($config) ); + return $config_out; +} + sub run { my ($class, @args) = @_; local @ARGV = @args; @@ -53,42 +106,7 @@ sub run { 'state=s@' => \@state, ); - my $config = YAML::Load( path($config_file)->slurp ); - my $pg; - if ($db_config_file) { - my $db_config = YAML::Load( path($db_config_file)->slurp ); - $config->{FMS_DB_PORT} = $db_config->{FMS_DB_PORT}; - $config->{FMS_DB_NAME} = $db_config->{FMS_DB_NAME}; - $config->{FMS_DB_USER} = $db_config->{FMS_DB_USER}; - $config->{FMS_DB_HOST} = $db_config->{FMS_DB_HOST}; - $config->{FMS_DB_PASS} = $db_config->{FMS_DB_PASS}; - } - else { - warn "Spinning up a Pg cluster/database...\n"; - $pg = Test::PostgreSQL->new(); - - warn sprintf "# Connected to %s\n", $pg->dsn; - - my $dbh = DBI->connect($pg->dsn); - - my $tmpwarn = $SIG{__WARN__}; - $SIG{__WARN__} = - sub { print STDERR @_ if $_[0] !~ m/NOTICE: CREATE TABLE/; }; - $dbh->do( path('db/schema.sql')->slurp ) or die $!; - $dbh->do( path('db/fixture.sql')->slurp ) or die $!; - $dbh->do( path('db/generate_secret.sql')->slurp ) or die $!; - $SIG{__WARN__} = $tmpwarn; - - $config->{FMS_DB_PORT} = $pg->port; - $config->{FMS_DB_NAME} = 'test'; - $config->{FMS_DB_USER} = 'postgres'; - $config->{FMS_DB_HOST} = 'localhost'; - $config->{FMS_DB_PASS} = ''; - } - - my $config_out = "general-test-autogenerated.$$.yml"; - path("conf/$config_out")->spew( YAML::Dump($config) ); - + my $config_out = $class->get_config({ config_file => $config_file, db_config_file => $db_config_file }); local $ENV{FMS_OVERRIDE_CONFIG} = $config_out; my $prove = App::Prove->new; |