[LON-CAPA-cvs] cvs: loncom /interface loncommon.pm /node.js/axe AxeRunner.pm lonaxe.pl

raeburn raeburn at source.lon-capa.org
Thu Jul 30 14:26:18 EDT 2026


raeburn		Thu Jul 30 18:26:18 2026 EDT

  Modified files:              
    /loncom/node.js/axe	lonaxe.pl AxeRunner.pm 
    /loncom/interface	loncommon.pm 
  Log:
  - Accessibility testing using axe-core and puppeteer (node.js) using a
    headless chromium web browser.
    - Display information about URLs which were in compliance, but which had
      incomplete tests, and include access to details about those tests.
    - For non-compliant URLs, detailed information about incomplete tests 
      appended to file containing details about non-compliance.
    - In listing of recent accessibility tests, omit files with no content
      and float the three tables (if present) alongside one another.
  
  
-------------- next part --------------
Index: loncom/node.js/axe/lonaxe.pl
diff -u loncom/node.js/axe/lonaxe.pl:1.5 loncom/node.js/axe/lonaxe.pl:1.6
--- loncom/node.js/axe/lonaxe.pl:1.5	Sat Jul 25 15:47:21 2026
+++ loncom/node.js/axe/lonaxe.pl	Thu Jul 30 18:26:18 2026
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 $|=1;
-# $Id: lonaxe.pl,v 1.5 2026/07/25 15:47:21 raeburn Exp $
+# $Id: lonaxe.pl,v 1.6 2026/07/30 18:26:18 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -64,6 +64,8 @@
 $outfile =~s/\.dat$/.txt/;
 my $csvfile = $outfile;
 $csvfile =~s/\.txt/.csv/;
+my $logfile = $filename;
+$logfile =~s/\.dat$/.log/;
 my %perlvar=%{&LONCAPA::Configuration::read_conf('loncapa.conf')};
 &Apache::lonlocal::get_language_handle();
 
@@ -170,7 +172,7 @@
 my $lonhost = $perlvar{'lonHostID'};
 my $spooldir = $perlvar{'lonAxeDir'};
 my $hostname = &Apache::lonnet::hostname($lonhost);
-my ($handle,$csvlink,$detailslink,$showlevel,$lock);
+my ($handle,$csvlink,$detailslink,$uncertainlink,$showlevel,$lock);
 if ($wcag =~ /^2(0|1|2)(a{1,3})$/) {
     $showlevel = "WCAG 2.$1 ".uc($2);
 } else {
@@ -183,16 +185,20 @@
              res => 'Resource',
              sta => 'Status',
              vio => 'Violations',
+             inc => 'Incompletes',
              cno => 'Could not open files for output',
              nor => 'No resources found to check',
              com => 'Number of resources in compliance',
+             unk => 'Number of resources in compliance, but with incomplete tests',
              not => 'Number of resources not in compliance',
              sum => 'Results summary (CSV format)',
              det => 'Details for non-compliant resources (plain text)',
+             inf => 'Details for resources with incomplete tests only (plain text)',
              err => 'Errors during accessibility checking',
              lau => 'Launch of Accessibility checking failed',
              pass => 'pass',
              fail => 'fail',
+             skip => 'skip',   
              invalid => 'Invalid compliance level or invalid URL',
              nolistener => 'No listener available to receive URL',
 );
@@ -201,6 +207,7 @@
     my $stem = $1;
     $csvlink = "/axespool/$stem.csv";
     $detailslink = "/axespool/$stem.txt";
+    $uncertainlink = "/axespool/$stem.log";
 } else {
     print &Apache::loncommon::end_page();
     exit;
@@ -232,7 +239,7 @@
                            '<br /></div>'.
                            '<div style="padding:0;clear:both;margin:0;border:0"></div>';
             my %prog_state = &Apache::lonhtmlcommon::Create_PrgWin('',$number_of_files,$preamble);
-            my (%errors, at passed, at failed);
+            my (%errors, at passed, at uncertain, at failed);
             print "<br />";
             if (open($fh,'<',$filename)) {
                 my @items;
@@ -242,9 +249,9 @@
                 }
                 close($fh);
                 if (@items) {
-                    my ($outfh,$csvfh);
-                    if ((open($outfh,'>',$outfile)) && (open($csvfh,'>',$csvfile))) {
-                        print $csvfh "\"$lt{'res'}\",\"$lt{'sta'}\",\"$lt{'vio'}\"\n";
+                    my ($outfh,$csvfh,$logfh);
+                    if ((open($outfh,'>',$outfile)) && (open($csvfh,'>',$csvfile)) && (open($logfh,'>',$logfile))) {
+                        print $csvfh "\"$lt{'res'}\",\"$lt{'sta'}\",\"$lt{'vio'}\",\"$lt{'inc'}\"\n";
                         foreach my $item (@items) {
                             my $querystr = '?inhibitmenu=yes';
                             my $url;
@@ -258,28 +265,49 @@
                             } else {
                                 $url = $privurl.$item;
                             }
-                            if ($url ne '') { 
-                                my ($violations, at details) =
-                                    &LONCAPA::AxeRunner::checkcompliance($protocol.'://'.$hostname.$url.$querystr);
+                            if ($url ne '') {
+                                my ($fails,$skips) = ('','');
+                                my ($violations,$incompletes) =
+                                    &LONCAPA::AxeRunner::checkcompliance($protocol.'://'.$hostname.$url.$querystr,
+                                                                         \$fails,\$skips);
                                 &Apache::lonhtmlcommon::Increment_PrgWin('',\%prog_state,'last resource');
                                 if ($violations eq -1) {
                                     push(@{$errors{'invalid'}},$url);
                                 } elsif ($violations eq '') {
                                     push(@{$errors{'nolistener'}},$url);
-                                } elsif ($violations eq 0) {
+                                } elsif (($violations eq 0) && ($incompletes eq 0)) {
                                     push(@passed,$url);
-                                    print $csvfh "\"$url\",\"$lt{'pass'}\",\"0\"\n";
+                                    print $csvfh "\"$url\",\"$lt{'pass'}\",\"0\",\"0\"\n";
                                 } else {
-                                    push(@failed,$url);
-                                    print $outfh &mt('[quant,_1,violation] for [_2]',
-                                                     $violations,$url)."\n".
-                                                     join("\n", at details)."\n--------------\n";
-                                    print $csvfh "\"$url\",\"$lt{'fail'}\",\"$violations\"\n";
+                                    my $status;
+                                    if ($violations) {
+                                        $status = $lt{'fail'};
+                                        push(@failed,$url);
+                                        print $outfh &mt('[quant,_1,violation] for [_2]',
+                                                         $violations,$url)."\n".
+                                                         $fails;
+                                        if ($incompletes) {
+                                            print $outfh "\n--\n".
+                                                         &mt('[quant,_1,incomplete] for [_2]',
+                                                             $incompletes,$url)."\n".
+                                                             $skips;
+                                        }
+                                        print $outfh "\n---------\n";
+                                    } elsif (($incompletes) && (!$violations)) {
+                                        $status = $lt{'skip'};
+                                        push(@uncertain,$url);
+                                        print $logfh &mt('[quant,_1,incomplete] for [_2]',
+                                                         $incompletes,$url)."\n".
+                                                         $skips."\n---------\n";
+
+                                    }
+                                    print $csvfh "\"$url\",\"$status\",\"$violations\",\"$incompletes\"\n";
                                 }
                             }
                         }
                         close($csvfh);
                         close($outfh);
+                        close($logfh);
                     } else {
                         print '<span class="LC_error">'.$lt{'cno'}.'</span><br />'."\n";
                     }
@@ -295,18 +323,22 @@
 // ]]>
 </script>
 ENDCLOSE
-            if (@passed || @failed) {
+            if (@passed || @failed || @uncertain) {
                 print '<h2 class="LC_heading_2">'.
                       &mt('Accessibility checking: compliance status (level [_1])',$showlevel).
                       '</h2>'."\n".
                       '<ul>'."\n".
                       '<li>'.$lt{'com'}.': '.scalar(@passed).'</li>'."\n".
+                      '<li>'.$lt{'unk'}.': '.scalar(@uncertain).'</li>'."\n".
                       '<li>'.$lt{'not'}.': '.scalar(@failed).'</li>'."\n".
                       '</ul>'."\n".
                       '<p><a href="'.$csvlink.'">'.$lt{'sum'}.'</a></p>';
                 if (@failed) {
                     print '<p><a href="'.$detailslink.'">'.$lt{'det'}.'</a></p>';
                 }
+                if (@uncertain) {
+                    print '<p><a href="'.$uncertainlink.'">'.$lt{'inf'}.'</a></p>';
+                }
             }
             if (keys(%errors)) {
                 print  '<h2 class="LC_heading_2">'.$lt{'err'}.'</h2>'."\n";
Index: loncom/node.js/axe/AxeRunner.pm
diff -u loncom/node.js/axe/AxeRunner.pm:1.3 loncom/node.js/axe/AxeRunner.pm:1.4
--- loncom/node.js/axe/AxeRunner.pm:1.3	Thu Jul 30 01:45:05 2026
+++ loncom/node.js/axe/AxeRunner.pm	Thu Jul 30 18:26:18 2026
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Accessibility Testing
 #
-# $Id: AxeRunner.pm,v 1.3 2026/07/30 01:45:05 raeburn Exp $
+# $Id: AxeRunner.pm,v 1.4 2026/07/30 18:26:18 raeburn Exp $
 #
 # The LearningOnline Network with CAPA
 #
@@ -89,22 +89,40 @@
 }
 
 sub checkcompliance {
-    my ($url) = @_;
+    my ($url,$fails,$skips) = @_;
     $url =~ s{^\s+|\s+$}{}g;
     if ($url =~ m{^https?://[\w.]+/}) {
         if ($pid) {
+            my ($count,$broken,$skip);
             print $chld_in 'URL ' . $url . "\n";
-            my $line = <$chld_out>;
-            chomp($line);
-            if ($line eq '0') {
-                return ($line);
-            } elsif ($line =~ /^(\d+)\s+/) {
-                my $count = $1;
-                $line =~s /^(\d+)\s+//;
-                return ($count,Data::Dumper->Dump(JSON::DWIW::deserialize($line)));
+            while (my $line = <$chld_out>) {
+                chomp($line);
+                last if ($line eq '');
+                if ($line eq '0') {
+                    $count = 0;
+                    last;
+                } elsif ($line =~ /^(\d+),([IV]),/) {
+                    my ($num,$type) = ($1,$2);
+                    $line =~s/^\d+,[IV],//;
+                    if ($line ne '') {
+                        if (($type eq 'V') && (ref($fails))) {
+                            $broken = $num;
+                            $$fails = Data::Dumper->Dump(JSON::DWIW::deserialize($line));
+                        } elsif (($type eq 'I') && (ref($skips))) {
+                            $skip = $num;
+                            $$skips = Data::Dumper->Dump(JSON::DWIW::deserialize($line));
+                        }
+                    }
+                }
+                last if (($broken ne '') && ($skip ne ''));
+            }
+            if ($count eq 0) {
+                return ($count,$count);
+            } else {
+                return ($broken,$skip);
             }
         } else {
-             return;
+             return ();
         }
     } else {
         return (-1);
@@ -142,11 +160,12 @@
 
  use lib '/home/httpd/lib/perl/';
  use LONCAPA::AxeRunner;
-
+ 
  if (&LONCAPA::AxeRunner::launch ( $cookieid,$handle,$linkid,$hostname ) eq 'ok') {
-     my ($violations,$details) =
-         &LONCAPA::AxeRunner::checkcompliance( $url );
-     &LONCAPA::AxeRunner::end();
+     my ($fails,$skips) = ('','');
+     my ($violations,$incompletes) =
+         &LONCAPA::AxeRunner::checkcompliance( $url, \$fails, \$skips );
+     &LONCAPA::AxeRunner::cleanup();
  }
 
 =head1 DESCRIPTION
@@ -159,7 +178,7 @@
 
 =over 4
 
-=item LONCAPA::AxeRunner::launch ( $handle,$linkid,$hostname );
+=item LONCAPA::AxeRunner::launch( $handle,$linkid,$hostname );
 
 =back
 
@@ -171,7 +190,7 @@
 
 =over 4
 
-=item LONCAPA::AxeRunner::cleanup ();
+=item LONCAPA::AxeRunner::cleanup();
 
 =back
 
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1532 loncom/interface/loncommon.pm:1.1533
--- loncom/interface/loncommon.pm:1.1532	Sun Jun 28 12:07:51 2026
+++ loncom/interface/loncommon.pm	Thu Jul 30 18:26:18 2026
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1532 2026/06/28 12:07:51 raeburn Exp $
+# $Id: loncommon.pm,v 1.1533 2026/07/30 18:26:18 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -21081,7 +21081,7 @@
     if ($spooltype eq 'axespool') {
         $spooldir = $Apache::lonnet::perlvar{'lonAxeDir'};
         $frag = 'axe';
-        @okexts = qw(csv txt);
+        @okexts = qw(csv txt log);
     } else {
         $spooldir = $Apache::lonnet::perlvar{'lonPrtDir'};
         $frag = 'printout';
@@ -21093,12 +21093,14 @@
         zip => 'Zip File',
         csv => 'CSV File',
         txt => 'Text File',
+        log => 'Text File',
     );
     my %heading = &Apache::lonlocal::texthash (
         zip => 'Recently generated printout zip files',
         pdf => 'Recently generated printouts',
         csv => 'Recently generated accessibility reports',
-        txt => 'Recently generated accessibility data',
+        txt => 'Recently generated non-compliance',
+        log => 'Recently generated non-completion', 
     );
     my $output;
     if ($spooldir) {
@@ -21116,6 +21118,11 @@
                 my %count;
                 foreach my $filename (@files) {
                     my ($ext) = ($filename =~ m/($regexp)$/);
+                    my ($cdev,$cino,$cmode,$cnlink,
+                        $cuid,$cgid,$crdev,$csize,
+                        $catime,$cmtime,$cctime,
+                        $cblksize,$cblocks)=stat($spooldir.'/'.$filename);
+                    next if (($csize == 0) && ($spooltype eq 'axespool'));
                     unless ($count{$ext}) {
                         $count{$ext} = 0;
                         $result{$ext} =
@@ -21127,10 +21134,6 @@
                            .'<th>'.&mt('File Size (Bytes)').'</th>'
                            .'</tr>'."\n";
                     }
-                    my ($cdev,$cino,$cmode,$cnlink,
-                        $cuid,$cgid,$crdev,$csize,
-                        $catime,$cmtime,$cctime,
-                        $cblksize,$cblocks)=stat($spooldir.'/'.$filename);
                     my $css_class = ($count{$ext} % 2)?'LC_odd_row':'LC_even_row';
                     $result{$ext} .=
                         '<tr class="'.$css_class.'" style="line-height: 170%;">'
@@ -21146,15 +21149,17 @@
                     if ($result{'zip'} || $result{'pdf'}) {
                         $output ='<hr />';
                     }
-                } elsif ($spooltype eq 'axespool') {
-                    if ($result{'csv'} || $result{'txt'}) {
-                        $output ='<hr />';
-                    }
                 }
                 foreach my $ext (@okexts) {
                     if ($result{$ext}) {
+                        if ($spooltype eq 'axespool') {
+                            $output .= '<div class="LC_floatleft">';
+                        }
                         $output .= $result{$ext}
                                   .'</table>'."\n";
+                        if ($spooltype eq 'axespool') {
+                            $output .= '</div>';
+                        }
                     }
                 }
             }


More information about the LON-CAPA-cvs mailing list