<commit_before>var timeStamp = 0 + ":" + 0 + ":" + 0 + "." + 0;
var previousVidWidth;
var previousVidHeight;
var lineNumber = 0;
var currentTime = 0;
var interval;
var videoPlayerLoaded = false;
var subtitleIsSet = false;
var guiIsvisible = false;
var isPlaying = false;
var isFullScreen = false;
var subtitleArray = [];
var isSeeking = false;
var video;

!window.jQuery && document.write(unescape('%3Cscript src="https://code.jquery.com/jquery-2.1.1.min.js%3E%3C%2Fscript%3E'))
/*
try{
    $('body').append("");
} catch (e){
    console.log("SubPlayer: jQuery not in header, appending now!");

    loadScript("https://code.jquery.com/jquery-2.1.1.min.js", function(){
        while(true){
            try{
                $('body').append("");
                break;
            } catch(e){
                console.log('not loaded yet');
            }
        }});

}*/

//loads video
function LoadSubPlayerJS(file, subtitle, div, w, h) {

    resetSubtitle();

    var vidwidth = 0;
    var vidheight = 0;

    if(w != null && w != "" && w != 0){
        vidwidth = w;
    } else {
        vidwidth = "100%";
    }

    if(h != null && h != "" && h != 0){
        vidheight = h;
    } else {
        vidheight = "100%";
    }

    if(!videoPlayerLoaded || previousVidHeight != h || previousVidWidth != w){

        if (!$("link[href='http://fonts.googleapis.com/icon?family=Material+Icons']").length){
            loadjscssfile("http://fonts.googleapis.com/icon?family=Material+Icons", "css");
        }
        if (!$("link[href='https://rawgit.com/EldinZenderink/SubPlayerJS/master/SubPlayerJS.css']").length){
            loadjscssfile("https://rawgit.com/EldinZenderink/SubPlayerJS/master/SubPlayerJS.css", "css");
        }
        if (!$("link[href='https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css']").length){
            loadjscssfile("https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css", "css");
        }
        $(div).html('\

\

\

\

\
                    <video id="SubPlayerVideo" width="' + vidwidth + '" height="' + vidheight + '">\
                    <source id="videoSource" src="">\
                        Your browser does not support HTML5 video.\
                    </video>\

\

'
        );
        videoPlayerLoaded = true;
    }

    previousVidWidth = w;
    previousVidHeight = h;

    video = document.getElementById('SubPlayerVideo');
    video.src = file;
    video.addEventListener('loadedmetadata', function () {
        console.log("IN LIBRARY: " + video.duration);
        var max = video.duration;
        $('.control-SPJS').html('
play_arrow | <input onclick="onSeekBarClick()" style="min-width: 80%; bottom: 9px;" type="range" id="seekbar" min="0" max="' + max + '" /> | fullscreen
');
        $('#seekbar').val(0).css("width", "80%").css("right", "5px");

        $('.outer-container-SPJS').on("change mousemove", function () {
            if (!guiIsvisible) {
               $('.outer-container-SPJS').css({ cursor: "auto"});
                guiIsvisible = true;
                console.log("GUI TOGGLE FIRST TIME");
                $('#allcontrols').fadeToggle();
                setTimeout(function () { $('#allcontrols').fadeToggle(); $('.outer-container-SPJS').css({ cursor: "none"}); guiIsvisible = false; console.log("GUI TOGGLE SECOND TIME"); }, 4000);
            }
        });

        if(subtitle != "" && subtitle != null && subtitle != 0){
            setSubtitle(subtitle);
        } else {
            subtitleIsSet = false;
        }

        $('#allcontrols').hide();

        setTimeout(function(){
            setInterval(function(){if(!isSeeking){$('#seekbar').val(video.currentTime);}}, 500);
        }, 0);

        video.onseeking = function () {
            isSeeking = true;
        }

        getTimeStamp();
    });

}

function startPlayVideo() {
    if (!isPlaying) {
        video.play();

        $('#playpause').html('pause');
        isPlaying = true;
    } else {
        video.pause();

        $('#playpause').html('play_arrow');
        isPlaying = false;
    }
}

function onSeekBarClick() {
    var currentPosition = $('#seekbar').val();
    video.currentTime = currentPosition;
    console.log(currentPosition);
}

function makeFullScreen() {
    var i = document.getElementsByClassName("outer-container-SPJS")[0];

    // go full-screen
    if (i.requestFullscreen) {
        i.requestFullscreen();
    } else if (i.webkitRequestFullscreen) {
        i.webkitRequestFullscreen();
    } else if (i.mozRequestFullScreen) {
        i.mozRequestFullScreen();
    } else if (i.msRequestFullscreen) {
        i.msRequestFullscreen();
    }
    if (!isFullScreen) {
        console.log("going into fullscreen");

         $('#SubPlayerVideo').css({
            position: 'fixed', //or fixed depending on needs
            top: 0,
            left: 0,
            height: '100%',
            width: '100%'
        });

        $('.video-overlay-SPJS').css({
            position: 'fixed', //or fixed depending on needs
            top: '85%',
            left: 0,
            height: '100%',
            width: '100%'
        });

        $('.control-SPJS').css({
            position: 'fixed', //or fixed depending on needs
            top: '85%',
            left: 0,
            height: '100%',
            width: '100%'
        });

        isFullScreen = true;
    } else {
        console.log("exiting fullscreen");
        if (document.exitFullscreen) {
            document.exitFullscreen();
        } else if (document.webkitExitFullscreen) {
            document.webkitExitFullscreen();
        } else if (document.mozCancelFullScreen) {
            document.mozCancelFullScreen();
        } else if (document.msExitFullscreen) {
            document.msExitFullscreen();
        }

        $('#SubPlayerVideo').css({
            position: 'relative',
            width: '100%'
        });

        $('.video-overlay-SPJS').css({
            position: 'absolute', //or fixed depending on needs
            top: '85%',
            left: 0,
            height: '100%',
            width: '100%'
        });

        $('.control-SPJS').css({
            position: 'absolute', //or fixed depending on needs
            top: '85%',
            left: 0,
            height: '100%',
            width: '100%'
        });
        isFullScreen = false;
    }

}

function setSubtitle(subtitleurl) {
    var extension = subtitleurl.replace(/^.*\./, '');
    $.ajax({
        url: subtitleurl,
        type: 'get',
        async: false,
        success: function (data) {
            switch(extension){
                case "ass":
                    console.log("SubPlayerJS: SSA (SubStationAlpha) Supported!");
                    parseSubStationAlpha(data);
                    break;
                case "srt":
                    console.log("SubPlayerJS: Comming soon!");
                    break;
                case "vtt":
                    console.log("SubPlayerJS: Comming soon!");
                    break;
                case "sub":
                     console.log("SubPlayerJS: Maybe supported in future!");
                    break;
                case "smi":
                    console.log("SubPlayerJS: Maybe supported in future!");
                    break;
                case "usf":
                    console.log("SubPlayerJS: Maybe supported in future!");
                    break;
                default:
                    console.log("SubPlayerJS: Subtitle with extension: " + extension + " is NOT supported!");
                    break;
            }
            console.log("SubPlayerJS: Succesfully read subtitle!");
        },
        error: function (err) {
            console.log("SubPlayerJS: FAILED TO LOAD SUBTITLE: " + err);
            subtitleIsSet = false;
        }
    });
}

function parseSubStationAlpha(ssa){

    var lines = ssa.split("\n");
    $.each(lines, function (key, line) {
        if (line.indexOf("Dialogue") > -1) {
            var parts = line.split(',');
            parts[parts.indexOf(parts[1])] = timeStampToSeconds(parts[1]);
            parts[parts.indexOf(parts[2])] = timeStampToSeconds(parts[2]);
            subtitleArray.push(parts);
        }
    });

    subtitleIsSet = true;

}

function resetSubtitle() {
    $('#subtitle').html('');
    try{
        clearInterval(interval);
    } catch (e) {
        console.log("no interval running");
    }
}

function timeStampToSeconds(timestamp) {
    var parts = timestamp.split(':');
    var hour = parts[0];
    var minute = parts[1];
    var second = parts[2];
    var totalSeconds = hour * 3600 + minute * 60 + parseInt(second);
    return totalSeconds;
}

function getTimeStamp() {
    interval = setInterval(function () {
        var curTimeSecond = video.currentTime;
        currentTime = curTimeSecond;
        if(subtitleIsSet){
            setTimeout(showSubtitle(curTimeSecond), 0);
        }
    }, 100);
}

function showSubtitle(time) {
    var localArray = subtitleArray;
    if(!isSeeking){
         try{

            var currentText = localArray[lineNumber];
            var secondOfTimeStart = currentText[1];
            var secondOfTimeEnd = currentText[2];

            if (time < secondOfTimeStart) {
                $('#subtitle').html('');
            } else {
                if (time > secondOfTimeEnd) {
                    lineNumber++;
                } else {
                    var fullText = "";
                    for (var i = 9; i < currentText.length; i++) {
                        fullText = fullText + "," + currentText[i];
                    }
                    $('#subtitle').html(fullText.substring(1).replace("\\N", "
"));
                }
            }
        } catch (e) {
            console.log("something went wrong while reading subtitle at time stamp: " );
            console.log("CURRENT: " + time);
            console.log("ERROR: " + e);
        }
    } else {
        var index = 0;
        $('#subtitle').html('');
        var arrayLength = localArray.length;
        for(var i = 0; i < arrayLength; i++){
            var timeStart = parseInt(localArray[i][1]);
            var timeEnd = parseInt(localArray[i][2]);
            //console.log("SubPlayerJS: INDEX SEARCH ON TIMESTART: " + timeStart + ", TIMEEND: " + timeEnd + " WITH CURRENT TIME: " + time);
            //console.log(localArray);

            if (time > timeStart) {
                //console.log("SubPlayerJS: INDEX SEARCH ON TIMESTART: " + timeStart + ", TIMEEND: " + timeEnd + " WITH CURRENT TIME: " + time);
                //console.log("SubPlayerJS: FOUND SUB POS AT: " + i);
                lineNumber = i;
            }
        }
        isSeeking = false;
    }

}

function loadjscssfile(filename, filetype){
    if (filetype=="js"){ //if filename is a external JavaScript file
        var fileref=document.createElement('script')
        fileref.setAttribute("type","text/javascript")
        fileref.setAttribute("src", filename)
    }
    else if (filetype=="css"){ //if filename is an external CSS file
        var fileref=document.createElement("link")
        fileref.setAttribute("rel", "stylesheet")
        fileref.setAttribute("type", "text/css")
        fileref.setAttribute("href", filename)
    }
    if (typeof fileref!="undefined")
        document.getElementsByTagName("head")[0].appendChild(fileref)
}

function loadScript(url, callback)
{
    // Adding the script tag to the head as suggested before
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    script.onreadystatechange = callback;
    script.onload = callback;

    // Fire the loading
    head.appendChild(script);
}<commit_msg>jQuery<commit_after>var timeStamp = 0 + ":" + 0 + ":" + 0 + "." + 0;
var previousVidWidth;
var previousVidHeight;
var lineNumber = 0;
var currentTime = 0;
var interval;
var videoPlayerLoaded = false;
var subtitleIsSet = false;
var guiIsvisible = false;
var isPlaying = false;
var isFullScreen = false;
var subtitleArray = [];
var isSeeking = false;
var video;

!window.jQuery && document.write(unescape('%3Cscript src="https://code.jquery.com/jquery-2.1.1.min.js%3E%3C%2Fscript%3E'))
/*
try{
    $('body').append("");
} catch (e){
    console.log("SubPlayer: jQuery not in header, appending now!");

    loadScript("https://code.jquery.com/jquery-2.1.1.min.js", function(){
        while(true){
            try{
                $('body').append("");
                break;
            } catch(e){
                console.log('not loaded yet');
            }
        }});

}*/

//loads video
function LoadSubPlayerJS(file, subtitle, div, w, h) {

    resetSubtitle();

    var vidwidth = 0;
    var vidheight = 0;

    if(w != null && w != "" && w != 0){
        vidwidth = w;
    } else {
        vidwidth = "100%";
    }

    if(h != null && h != "" && h != 0){
        vidheight = h;
    } else {
        vidheight = "100%";
    }

    if(!videoPlayerLoaded || previousVidHeight != h || previousVidWidth != w){

        if (!$("link[href='http://fonts.googleapis.com/icon?family=Material+Icons']").length){
            loadjscssfile("http://fonts.googleapis.com/icon?family=Material+Icons", "css");
        }
        if (!$("link[href='https://rawgit.com/EldinZenderink/SubPlayerJS/master/SubPlayerJS.css']").length){
            loadjscssfile("https://rawgit.com/EldinZenderink/SubPlayerJS/master/SubPlayerJS.css", "css");
        }
        if (!$("link[href='https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css']").length){
            loadjscssfile("https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css", "css");
        }
        $(div).html('\

\

\

\

\
                    <video id="SubPlayerVideo" width="' + vidwidth + '" height="' + vidheight + '">\
                    <source id="videoSource" src="">\
                        Your browser does not support HTML5 video.\
                    </video>\

\

'
        );
        videoPlayerLoaded = true;
    }

    previousVidWidth = w;
    previousVidHeight = h;

    video = document.getElementById('SubPlayerVideo');
    video.src = file;
    video.addEventListener('loadedmetadata', function () {
        console.log("IN LIBRARY: " + video.duration);
        var max = video.duration;
        $('.control-SPJS').html('
play_arrow | <input onclick="onSeekBarClick()" style="min-width: 80%; bottom: 9px;" type="range" id="seekbar" min="0" max="' + max + '" /> | fullscreen
');
        $('#seekbar').val(0).css("width", "80%").css("right", "5px");

        $('.outer-container-SPJS').on("change mousemove", function () {
            if (!guiIsvisible) {
               $('.outer-container-SPJS').css({ cursor: "auto"});
                guiIsvisible = true;
                console.log("GUI TOGGLE FIRST TIME");
                $('#allcontrols').fadeToggle();
                setTimeout(function () { $('#allcontrols').fadeToggle(); $('.outer-container-SPJS').css({ cursor: "none"}); guiIsvisible = false; console.log("GUI TOGGLE SECOND TIME"); }, 4000);
            }
        });

        if(subtitle != "" && subtitle != null && subtitle != 0){
            setSubtitle(subtitle);
        } else {
            subtitleIsSet = false;
        }

        $('#allcontrols').hide();

        setTimeout(function(){
            setInterval(function(){if(!isSeeking){$('#seekbar').val(video.currentTime);}}, 500);
        }, 0);

        video.onseeking = function () {
            isSeeking = true;
        }

        getTimeStamp();
    });

}

function startPlayVideo() {
    if (!isPlaying) {
        video.play();

        $('#playpause').html('pause');
        isPlaying = true;
    } else {
        video.pause();

        $('#playpause').html('play_arrow');
        isPlaying = false;
    }
}

function onSeekBarClick() {
    var currentPosition = $('#seekbar').val();
    video.currentTime = currentPosition;
    console.log(currentPosition);
}

function makeFullScreen() {
    var i = document.getElementsByClassName("outer-container-SPJS")[0];

    // go full-screen
    if (i.requestFullscreen) {
        i.requestFullscreen();
    } else if (i.webkitRequestFullscreen) {
        i.webkitRequestFullscreen();
    } else if (i.mozRequestFullScreen) {
        i.mozRequestFullScreen();
    } else if (i.msRequestFullscreen) {
        i.msRequestFullscreen();
    }
    if (!isFullScreen) {
        console.log("going into fullscreen");

         $('#SubPlayerVideo').css({
            position: 'fixed', //or fixed depending on needs
            top: 0,
            left: 0,
            height: '100%',
            width: '100%'
        });

        $('.video-overlay-SPJS').css({
            position: 'fixed', //or fixed depending on needs
            top: '85%',
            left: 0,
            height: '100%',
            width: '100%'
        });

        $('.control-SPJS').css({
            position: 'fixed', //or fixed depending on needs
            top: '85%',
            left: 0,
            height: '100%',
            width: '100%'
        });

        isFullScreen = true;
    } else {
        console.log("exiting fullscreen");
        if (document.exitFullscreen) {
            document.exitFullscreen();
        } else if (document.webkitExitFullscreen) {
            document.webkitExitFullscreen();
        } else if (document.mozCancelFullScreen) {
            document.mozCancelFullScreen();
        } else if (document.msExitFullscreen) {
            document.msExitFullscreen();
        }

        $('#SubPlayerVideo').css({
            position: 'relative',
            width: '100%'
        });

        $('.video-overlay-SPJS').css({
            position: 'absolute', //or fixed depending on needs
            top: '85%',
            left: 0,
            height: '100%',
            width: '100%'
        });

        $('.control-SPJS').css({
            position: 'absolute', //or fixed depending on needs
            top: '85%',
            left: 0,
            height: '100%',
            width: '100%'
        });
        isFullScreen = false;
    }

}

function setSubtitle(subtitleurl) {
    var extension = subtitleurl.replace(/^.*\./, '');
    $.ajax({
        url: subtitleurl,
        type: 'get',
        async: false,
        success: function (data) {
            switch(extension){
                case "ass":
                    console.log("SubPlayerJS: SSA (SubStationAlpha) Supported!");
                    parseSubStationAlpha(data);
                    break;
                case "srt":
                    console.log("SubPlayerJS: Comming soon!");
                    break;
                case "vtt":
                    console.log("SubPlayerJS: Comming soon!");
                    break;
                case "sub":
                     console.log("SubPlayerJS: Maybe supported in future!");
                    break;
                case "smi":
                    console.log("SubPlayerJS: Maybe supported in future!");
                    break;
                case "usf":
                    console.log("SubPlayerJS: Maybe supported in future!");
                    break;
                default:
                    console.log("SubPlayerJS: Subtitle with extension: " + extension + " is NOT supported!");
                    break;
            }
            console.log("SubPlayerJS: Succesfully read subtitle!");
        },
        error: function (err) {
            console.log("SubPlayerJS: FAILED TO LOAD SUBTITLE: " + err);
            subtitleIsSet = false;
        }
    });
}

function parseSubStationAlpha(ssa){

    var lines = ssa.split("\n");
    $.each(lines, function (key, line) {
        if (line.indexOf("Dialogue") > -1) {
            var parts = line.split(',');
            parts[parts.indexOf(parts[1])] = timeStampToSeconds(parts[1]);
            parts[parts.indexOf(parts[2])] = timeStampToSeconds(parts[2]);
            subtitleArray.push(parts);
        }
    });

    subtitleIsSet = true;

}

function resetSubtitle() {
    $('#subtitle').html('');
    try{
        clearInterval(interval);
    } catch (e) {
        console.log("no interval running");
    }
}

function timeStampToSeconds(timestamp) {
    var parts = timestamp.split(':');
    var hour = parts[0];
    var minute = parts[1];
    var second = parts[2];
    var totalSeconds = hour * 3600 + minute * 60 + parseInt(second);
    return totalSeconds;
}

function getTimeStamp() {
    interval = setInterval(function () {
        var curTimeSecond = video.currentTime;
        currentTime = curTimeSecond;
        if(subtitleIsSet){
            setTimeout(showSubtitle(curTimeSecond), 0);
        }
    }, 100);
}

function showSubtitle(time) {
    var localArray = subtitleArray;
    if(!isSeeking){
         try{

            var currentText = localArray[lineNumber];
            var secondOfTimeStart = currentText[1];
            var secondOfTimeEnd = currentText[2];

            if (time < secondOfTimeStart) {
                $('#subtitle').html('');
            } else {
                if (time > secondOfTimeEnd) {
                    lineNumber++;
                } else {
                    var fullText = "";
                    for (var i = 9; i < currentText.length; i++) {
                        fullText = fullText + "," + currentText[i];
                    }
                    $('#subtitle').html(fullText.substring(1).replace("\\N", "
"));
                }
            }
        } catch (e) {
            console.log("something went wrong while reading subtitle at time stamp: " );
            console.log("CURRENT: " + time);
            console.log("ERROR: " + e);
        }
    } else {
        var index = 0;
        $('#subtitle').html('');
        var arrayLength = localArray.length;
        for(var i = 0; i < arrayLength; i++){
            var timeStart = parseInt(localArray[i][1]);
            var timeEnd = parseInt(localArray[i][2]);
            //console.log("SubPlayerJS: INDEX SEARCH ON TIMESTART: " + timeStart + ", TIMEEND: " + timeEnd + " WITH CURRENT TIME: " + time);
            //console.log(localArray);

            if (time > timeStart) {
                //console.log("SubPlayerJS: INDEX SEARCH ON TIMESTART: " + timeStart + ", TIMEEND: " + timeEnd + " WITH CURRENT TIME: " + time);
                //console.log("SubPlayerJS: FOUND SUB POS AT: " + i);
                lineNumber = i;
            }
        }
        isSeeking = false;
    }

}

function loadjscssfile(filename, filetype){
    if (filetype=="js"){ //if filename is a external JavaScript file
        var fileref=document.createElement('script')
        fileref.setAttribute("type","text/javascript")
        fileref.setAttribute("src", filename)
    }
    else if (filetype=="css"){ //if filename is an external CSS file
        var fileref=document.createElement("link")
        fileref.setAttribute("rel", "stylesheet")
        fileref.setAttribute("type", "text/css")
        fileref.setAttribute("href", filename)
    }
    if (typeof fileref!="undefined")
        document.getElementsByTagName("head")[0].appendChild(fileref)
}

function loadScript(url, callback)
{
    // Adding the script tag to the head as suggested before
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    script.onreadystatechange = callback;
    script.onload = callback;

    // Fire the loading
    head.appendChild(script);
}<|endoftext|>


<commit_before>import buildUrl from 'build-url';
import moment from 'moment';

import { BaseScraper, LOGIN_RESULT } from './base-scraper';
import { waitForRedirect } from '../helpers/navigation';
import { waitUntilElementFound } from '../helpers/elements-interactions';

const BASE_URL = 'https://online.leumi-card.co.il';
const DATE_FORMAT = 'DD/MM/YYYY';

function redirectOrDialog(page) {
  return Promise.race([
    waitForRedirect(page),
    waitUntilElementFound(page, 'popupWrongDetails', true),
  ]);
}

function getAccountNumbers(page) {
  return page.evaluate(() => {
    const creditCardDetailsList = document.getElementsByClassName('creditCard_name');
    const accountNumbers = [];
    for (let i = 0; i < creditCardDetailsList.length; i += 1) {
      const dirtyAccountNumber = creditCardDetailsList[i].lastChild.textContent;
      const accountNumber = dirtyAccountNumber.trim().replace('(', '').replace(')', '');
      accountNumbers.push(accountNumber);
    }
    return accountNumbers;
  });
}

function getTransactionsUrl(accountIndex, tableType, startDate) {
  const fromDateStr = moment(startDate).format(DATE_FORMAT);
  const toDateStr = moment().format(DATE_FORMAT);

  return buildUrl(BASE_URL, {
    path: 'Popups/Print.aspx',
    queryParams: {
      PrintType: 'TransactionsTable',
      CardIndex: accountIndex,
      TableType: tableType,
      ActionType: 'Dates',
      FilterParam: 'AllTranactions',
      FromDate: fromDateStr,
      ToDate: toDateStr,
      SortDirection: 'Ascending',
      SortParam: 'PaymentDate',
    },
  });
}

function getLoadedRawTransactions(page) {
  return page.evaluate(() => {
    const tables = document.getElementsByTagName('table');
    const table = tables[0];

    const rows = table.getElementsByTagName('tr');

    const txns = [];
    for (let i = 0; i < rows.length; i += 1) {
      if (rows[i].id && rows[i].id.indexOf('tbl1') >= 0) {
        const cells = rows[i].getElementsByTagName('td');

        const dateStr = cells[1].textContent.trim();
        const processedDateStr = cells[2].textContent.trim();
        const amountStr = cells[6].textContent;
        const description = cells[3].textContent;

        const txn = {
          dateStr,
          processedDateStr,
          amountStr,
          description,
        };
        txns.push(txn);
      }
    }
    return txns;
  });
}

async function fetchTransactionsByType(page, accountIndex, transactionsType, startDate) {
  const url = getTransactionsUrl(accountIndex, transactionsType, startDate);
  await page.goto(url);
  const current = await page.url();
  if (current.includes('error.aspx')) {
    return [];
  }
  await waitUntilElementFound(page, 'tbl1_lvTransactions_lnkPurchaseDate');

  const rawTxns = await getLoadedRawTransactions(page);
  const txns = rawTxns.map((txn) => {
    return {
      date: moment(txn.dateStr, DATE_FORMAT).toDate(),
      processedDate: moment(txn.processedDateStr, DATE_FORMAT).toDate(),
      amount: parseFloat(txn.amountStr.replace(',', '')),
      description: txn.description.trim(),
    };
  });
  return txns;
}

async function fetchTransactions(page, accountIndex, options) {
  const defaultStartMoment = moment().subtract(1, 'years');
  let startDate = options.startDate || defaultStartMoment.toDate();
  const startMoment = moment.max(defaultStartMoment, moment(startDate));
  startDate = startMoment.toDate();

  const localTxns = await fetchTransactionsByType(page, accountIndex, 'NisTransactions', startDate);
  const futureLocalTxns = await fetchTransactionsByType(page, accountIndex, 'FutureNisTransactions', startDate);
  const foreignTxns = await fetchTransactionsByType(page, accountIndex, 'ForeignTransactions', startDate);
  const futureForeignTxns = await fetchTransactionsByType(page, accountIndex, 'FutureForeignTransactions', startDate);
  const allTxns = [...localTxns, ...futureLocalTxns, ...foreignTxns, ...futureForeignTxns];
  allTxns.sort((txn1, txn2) => {
    if (txn1.date.getTime() === txn2.date.getTime()) {
      return 0;
    }
    return txn1.date < txn2.date ? -1 : 1;
  });
  return allTxns;
}

async function getAccountData(page, options) {
  const accountsPage = `${BASE_URL}/Registred/Transactions/ChargesDeals.aspx`;
  await page.goto(accountsPage);

  const accountNumbers = await getAccountNumbers(page);
  const txns = await fetchTransactions(page, 0, options);

  return {
    success: true,
    accountNumber: accountNumbers[0],
    txns,
  };
}

function getPossibleLoginResults() {
  const urls = {};
  urls[LOGIN_RESULT.SUCCESS] = `${BASE_URL}/Registred/HomePage.aspx`;
  urls[LOGIN_RESULT.INVALID_PASSWORD] = `${BASE_URL}/Anonymous/Login/CardHoldersLogin.aspx`;
  return urls;
}

function createLoginFields(inputGroupName, credentials) {
  return [
    { id: `${inputGroupName}_txtUserName`, value: credentials.username },
    { id: `${inputGroupName}_txtPassword`, value: credentials.password },
  ];
}

class LeumiCardScraper extends BaseScraper {
  constructor() {
    super('leumi-card');
  }

  getLoginOptions(credentials) {
    const inputGroupName = 'PlaceHolderMain_CardHoldersLogin1';
    return {
      loginUrl: `${BASE_URL}/Anonymous/Login/CardHoldersLogin.aspx`,
      fields: createLoginFields(inputGroupName, credentials),
      submitButtonId: `${inputGroupName}_btnLogin`,
      postAction: async () => redirectOrDialog(this.page),
      possibleResults: getPossibleLoginResults(),
    };
  }

  async fetchData() {
    return getAccountData(this.page, this.options);
  }
}

export default LeumiCardScraper;
<commit_msg>make leumi cards amounts negative<commit_after>import buildUrl from 'build-url';
import moment from 'moment';

import { BaseScraper, LOGIN_RESULT } from './base-scraper';
import { waitForRedirect } from '../helpers/navigation';
import { waitUntilElementFound } from '../helpers/elements-interactions';

const BASE_URL = 'https://online.leumi-card.co.il';
const DATE_FORMAT = 'DD/MM/YYYY';

function redirectOrDialog(page) {
  return Promise.race([
    waitForRedirect(page),
    waitUntilElementFound(page, 'popupWrongDetails', true),
  ]);
}

function getAccountNumbers(page) {
  return page.evaluate(() => {
    const creditCardDetailsList = document.getElementsByClassName('creditCard_name');
    const accountNumbers = [];
    for (let i = 0; i < creditCardDetailsList.length; i += 1) {
      const dirtyAccountNumber = creditCardDetailsList[i].lastChild.textContent;
      const accountNumber = dirtyAccountNumber.trim().replace('(', '').replace(')', '');
      accountNumbers.push(accountNumber);
    }
    return accountNumbers;
  });
}

function getTransactionsUrl(accountIndex, tableType, startDate) {
  const fromDateStr = moment(startDate).format(DATE_FORMAT);
  const toDateStr = moment().format(DATE_FORMAT);

  return buildUrl(BASE_URL, {
    path: 'Popups/Print.aspx',
    queryParams: {
      PrintType: 'TransactionsTable',
      CardIndex: accountIndex,
      TableType: tableType,
      ActionType: 'Dates',
      FilterParam: 'AllTranactions',
      FromDate: fromDateStr,
      ToDate: toDateStr,
      SortDirection: 'Ascending',
      SortParam: 'PaymentDate',
    },
  });
}

function getLoadedRawTransactions(page) {
  return page.evaluate(() => {
    const tables = document.getElementsByTagName('table');
    const table = tables[0];

    const rows = table.getElementsByTagName('tr');

    const txns = [];
    for (let i = 0; i < rows.length; i += 1) {
      if (rows[i].id && rows[i].id.indexOf('tbl1') >= 0) {
        const cells = rows[i].getElementsByTagName('td');

        const dateStr = cells[1].textContent.trim();
        const processedDateStr = cells[2].textContent.trim();
        const amountStr = cells[6].textContent;
        const description = cells[3].textContent;

        const txn = {
          dateStr,
          processedDateStr,
          amountStr,
          description,
        };
        txns.push(txn);
      }
    }
    return txns;
  });
}

async function fetchTransactionsByType(page, accountIndex, transactionsType, startDate) {
  const url = getTransactionsUrl(accountIndex, transactionsType, startDate);
  await page.goto(url);
  const current = await page.url();
  if (current.includes('error.aspx')) {
    return [];
  }
  await waitUntilElementFound(page, 'tbl1_lvTransactions_lnkPurchaseDate');

  const rawTxns = await getLoadedRawTransactions(page);
  const txns = rawTxns.map((txn) => {
    return {
      date: moment(txn.dateStr, DATE_FORMAT).toDate(),
      processedDate: moment(txn.processedDateStr, DATE_FORMAT).toDate(),
      amount: -parseFloat(txn.amountStr.replace(',', '')),
      description: txn.description.trim(),
    };
  });
  return txns;
}

async function fetchTransactions(page, accountIndex, options) {
  const defaultStartMoment = moment().subtract(1, 'years');
  let startDate = options.startDate || defaultStartMoment.toDate();
  const startMoment = moment.max(defaultStartMoment, moment(startDate));
  startDate = startMoment.toDate();

  const localTxns = await fetchTransactionsByType(page, accountIndex, 'NisTransactions', startDate);
  const futureLocalTxns = await fetchTransactionsByType(page, accountIndex, 'FutureNisTransactions', startDate);
  const foreignTxns = await fetchTransactionsByType(page, accountIndex, 'ForeignTransactions', startDate);
  const futureForeignTxns = await fetchTransactionsByType(page, accountIndex, 'FutureForeignTransactions', startDate);
  const allTxns = [...localTxns, ...futureLocalTxns, ...foreignTxns, ...futureForeignTxns];
  allTxns.sort((txn1, txn2) => {
    if (txn1.date.getTime() === txn2.date.getTime()) {
      return 0;
    }
    return txn1.date < txn2.date ? -1 : 1;
  });
  return allTxns;
}

async function getAccountData(page, options) {
  const accountsPage = `${BASE_URL}/Registred/Transactions/ChargesDeals.aspx`;
  await page.goto(accountsPage);

  const accountNumbers = await getAccountNumbers(page);
  const txns = await fetchTransactions(page, 0, options);

  return {
    success: true,
    accountNumber: accountNumbers[0],
    txns,
  };
}

function getPossibleLoginResults() {
  const urls = {};
  urls[LOGIN_RESULT.SUCCESS] = `${BASE_URL}/Registred/HomePage.aspx`;
  urls[LOGIN_RESULT.INVALID_PASSWORD] = `${BASE_URL}/Anonymous/Login/CardHoldersLogin.aspx`;
  return urls;
}

function createLoginFields(inputGroupName, credentials) {
  return [
    { id: `${inputGroupName}_txtUserName`, value: credentials.username },
    { id: `${inputGroupName}_txtPassword`, value: credentials.password },
  ];
}

class LeumiCardScraper extends BaseScraper {
  constructor() {
    super('leumi-card');
  }

  getLoginOptions(credentials) {
    const inputGroupName = 'PlaceHolderMain_CardHoldersLogin1';
    return {
      loginUrl: `${BASE_URL}/Anonymous/Login/CardHoldersLogin.aspx`,
      fields: createLoginFields(inputGroupName, credentials),
      submitButtonId: `${inputGroupName}_btnLogin`,
      postAction: async () => redirectOrDialog(this.page),
      possibleResults: getPossibleLoginResults(),
    };
  }

  async fetchData() {
    return getAccountData(this.page, this.options);
  }
}

export default LeumiCardScraper;
<|endoftext|>


<commit_before>
var computeLayout = (function() {

  function fillNodes(node) {
    node.layout = {
      width: undefined,
      height: undefined,
      top: 0,
      left: 0
    };
    if (!node.style) {
      node.style = {};
    }
    if (!node.children) {
      node.children = [];
    }
    node.children.forEach(fillNodes);
  }

  function extractNodes(node) {
    var layout = node.layout;
    delete node.layout;
    if (node.children.length > 0) {
      layout.children = node.children.map(extractNodes);
    } else {
      delete node.children;
    }
    return layout;
  }

  function capitalizeFirst(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }

  function getSpacing(node, type, suffix, location) {
    var key = type + capitalizeFirst(location) + suffix;
    if (key in node.style) {
      return node.style[key];
    }

    key = type + suffix;
    if (key in node.style) {
      return node.style[key];
    }

    return 0;
  }

  function getPositiveSpacing(node, type, suffix, location) {
    var key = type + capitalizeFirst(location) + suffix;
    if (key in node.style && node.style[key] >= 0) {
      return node.style[key];
    }

    key = type + suffix;
    if (key in node.style && node.style[key] >= 0) {
      return node.style[key];
    }

    return 0;
  }

  function isUndefined(value) {
    return value === undefined;
  }

  function getMargin(node, location) {
    return getSpacing(node, 'margin', '', location);
  }

  function getPadding(node, location) {
    return getPositiveSpacing(node, 'padding', '', location);
  }

  function getBorder(node, location) {
    return getPositiveSpacing(node, 'border', 'Width', location);
  }

  function getPaddingAndBorder(node, location) {
    return getPadding(node, location) + getBorder(node, location);
  }

  function getMarginAxis(node, axis) {
    return getMargin(node, leading[axis]) + getMargin(node, trailing[axis]);
  }

  function getPaddingAndBorderAxis(node, axis) {
    return getPaddingAndBorder(node, leading[axis]) + getPaddingAndBorder(node, trailing[axis]);
  }

  function getJustifyContent(node) {
    if ('justifyContent' in node.style) {
      return node.style.justifyContent;
    }
    return 'flex-start';
  }

  function getAlignItem(node, child) {
    if ('alignSelf' in child.style) {
      return child.style.alignSelf;
    }
    if ('alignItems' in node.style) {
      return node.style.alignItems;
    }
    return 'flex-start';
  }

  function getFlexDirection(node) {
    if ('flexDirection' in node.style) {
      return node.style.flexDirection;
    }
    return 'column';
  }

  function getPositionType(node) {
    if ('position' in node.style) {
      return node.style.position;
    }
    return 'relative';
  }

  function getFlex(node) {
    return node.style.flex === 1;
  }

  function getDimWithMargin(node, axis) {
    return node.layout[dim[axis]] + getMarginAxis(node, axis);
  }

  function isDimDefined(node, axis) {
    return !isUndefined(node.style[dim[axis]]) && node.style[dim[axis]] >= 0;
  }

  function isPosDefined(node, pos) {
    return !isUndefined(node.style[pos]);
  }

  function getPosition(node, pos) {
    if (pos in node.style) {
      return node.style[pos];
    }
    return 0;
  }

  // If both left and right are defined, then use left. Otherwise return
  // +left or -right depending on which is defined.
  function getRelativePosition(node, axis) {
    if (leading[axis] in node.style) {
      return getPosition(node, leading[axis]);
    }
    return -getPosition(node, trailing[axis]);
  }

  var leading = {
    row: 'left',
    column: 'top'
  };
  var trailing = {
    row: 'right',
    column: 'bottom'
  };
  var pos = {
    row: 'left',
    column: 'top'
  };
  var dim = {
    row: 'width',
    column: 'height'
  };

  function fmaxf(a, b) {
    if (a > b) {
      return a;
    }
    return b;
  }

  var CSS_FLEX_DIRECTION_ROW = 'row';
  var CSS_FLEX_DIRECTION_COLUMN = 'column';

  var CSS_JUSTIFY_FLEX_START = 'flex-start';
  var CSS_JUSTIFY_CENTER = 'center';
  var CSS_JUSTIFY_FLEX_END = 'flex-end';
  var CSS_JUSTIFY_SPACE_BETWEEN = 'space-between';
  var CSS_JUSTIFY_SPACE_AROUND = 'space-around';

  var CSS_ALIGN_FLEX_START = 'flex-start';
  var CSS_ALIGN_CENTER = 'center';
  var CSS_ALIGN_FLEX_END = 'flex-end';
  var CSS_ALIGN_STRETCH = 'stretch';

  var CSS_POSITION_RELATIVE = 'relative';
  var CSS_POSITION_ABSOLUTE = 'absolute';

  function layoutNode(node) {
    var/*css_flex_direction_t*/ mainAxis = getFlexDirection(node);
    var/*css_flex_direction_t*/ crossAxis = mainAxis === CSS_FLEX_DIRECTION_ROW ?
      CSS_FLEX_DIRECTION_COLUMN :
      CSS_FLEX_DIRECTION_ROW;

    var/*bool*/ mainDimInStyle = isDimDefined(node, mainAxis);
    if (isUndefined(node.layout[dim[mainAxis]]) && mainDimInStyle) {
      node.layout[dim[mainAxis]] = fmaxf(
        node.style[dim[mainAxis]],
        getPaddingAndBorderAxis(node, mainAxis)
      );
    }

    var/*bool*/ crossDimInStyle = isDimDefined(node, crossAxis);
    if (isUndefined(node.layout[dim[crossAxis]]) && crossDimInStyle) {
      node.layout[dim[crossAxis]] = fmaxf(
        node.style[dim[crossAxis]],
        getPaddingAndBorderAxis(node, crossAxis)
      );
    }

    var/*float*/ mainContentDim = 0;
    var/*int*/ flexibleChildrenCount = 0;
    var/*int*/ absoluteChildrenCount = 0;
    for (var/*int*/ i = 0; i < node.children.length; ++i) {
      var/*css_node_t**/ child = node.children[i];
      if (isUndefined(node.layout[dim[mainAxis]]) ||
          getPositionType(child) === CSS_POSITION_ABSOLUTE ||
          !getFlex(child)) {
        layoutNode(child);
        if (getPositionType(child) === CSS_POSITION_RELATIVE) {
          mainContentDim += getDimWithMargin(child, mainAxis);
        } else {
          absoluteChildrenCount++;
        }
      } else {
        flexibleChildrenCount++;
        mainContentDim += getPaddingAndBorderAxis(child, mainAxis) + getMarginAxis(child, mainAxis);
      }
    }

    var/*float*/ leadingMainDim = 0;
    var/*float*/ betweenMainDim = 0;
    if (!isUndefined(node.layout[dim[mainAxis]])) {
      var/*float*/ remainingMainDim = node.layout[dim[mainAxis]] -
        getPaddingAndBorderAxis(node, mainAxis) -
        mainContentDim;

      if (flexibleChildrenCount) {
        var/*float*/ flexibleMainDim = remainingMainDim / flexibleChildrenCount;
        if (flexibleMainDim < 0) {
          flexibleMainDim = 0;
        }
        for (var/*int*/ i = 0; i < node.children.length; ++i) {
          var/*css_node_t**/ child = node.children[i];
          if (getPositionType(child) === CSS_POSITION_RELATIVE && getFlex(child)) {
            child.layout[dim[mainAxis]] = flexibleMainDim + getPaddingAndBorderAxis(child, mainAxis);
            layoutNode(child);
          }
        }
      } else {
        var/*css_justify_t*/ justifyContent = getJustifyContent(node);
        if (justifyContent === CSS_JUSTIFY_FLEX_START) {
          // Do nothing
        } else if (justifyContent === CSS_JUSTIFY_CENTER) {
          leadingMainDim = remainingMainDim / 2;
        } else if (justifyContent === CSS_JUSTIFY_FLEX_END) {
          leadingMainDim = remainingMainDim;
        } else if (justifyContent === CSS_JUSTIFY_SPACE_BETWEEN) {
          betweenMainDim = remainingMainDim / (node.children.length - absoluteChildrenCount - 1);
        } else if (justifyContent === CSS_JUSTIFY_SPACE_AROUND) {
          betweenMainDim = remainingMainDim / (node.children.length - absoluteChildrenCount);
          leadingMainDim = betweenMainDim / 2;
        }
      }
    }

    var/*float*/ crossDim = 0;
    var/*float*/ mainPos = getPaddingAndBorder(node, leading[mainAxis]) + leadingMainDim;
    for (var/*int*/ i = 0; i < node.children.length; ++i) {
      var/*css_node_t**/ child = node.children[i];
      if (getPositionType(child) === CSS_POSITION_ABSOLUTE && isPosDefined(child, leading[mainAxis])) {
        child.layout[pos[mainAxis]] = getPosition(child, leading[mainAxis]) +
          getBorder(node, leading[mainAxis]) +
          getMargin(child, leading[mainAxis]);
      } else {
        child.layout[pos[mainAxis]] += mainPos;
      }
      if (getPositionType(child) === CSS_POSITION_RELATIVE) {
        mainPos += getDimWithMargin(child, mainAxis) + betweenMainDim;

        if (!isUndefined(child.layout[dim[crossAxis]])) {
          var/*float*/ childCrossDim = getDimWithMargin(child, crossAxis);
          if (childCrossDim > crossDim) {
            crossDim = childCrossDim;
          }
        }
      }
    }

    mainPos += getPaddingAndBorder(node, trailing[mainAxis]);
    crossDim += getPaddingAndBorderAxis(node, crossAxis);

    if (isUndefined(node.layout[dim[mainAxis]]) && !mainDimInStyle) {
      node.layout[dim[mainAxis]] = fmaxf(mainPos, getPaddingAndBorderAxis(node, mainAxis));
    }
    if (isUndefined(node.layout[dim[crossAxis]])) {
      node.layout[dim[crossAxis]] = fmaxf(crossDim, getPaddingAndBorderAxis(node, crossAxis));
    }

    for (var/*int*/ i = 0; i < node.children.length; ++i) {
      var/*css_node_t**/ child = node.children[i];

      if (getPositionType(child) === CSS_POSITION_RELATIVE) {
        var/*css_align_t*/ alignItem = getAlignItem(node, child);
        var/*float*/ remainingCrossDim = node.layout[dim[crossAxis]] -
          getDimWithMargin(child, crossAxis) -
          getPaddingAndBorderAxis(node, crossAxis);

        var/*float*/ leadingCrossDim = getPaddingAndBorder(node, leading[crossAxis]);
        if (alignItem === CSS_ALIGN_FLEX_START) {
          // Do nothing
        } else if (alignItem === CSS_ALIGN_CENTER) {
          leadingCrossDim += remainingCrossDim / 2;
        } else if (alignItem === CSS_ALIGN_FLEX_END) {
          leadingCrossDim += remainingCrossDim;
        } else if (alignItem === CSS_ALIGN_STRETCH) {
          if (!isDimDefined(child, crossAxis)) {
            child.layout[dim[crossAxis]] = fmaxf(
              node.layout[dim[crossAxis]] -
                getPaddingAndBorderAxis(node, crossAxis) -
                getMarginAxis(child, crossAxis),
              getPaddingAndBorderAxis(child, crossAxis)
            );
          }
        }
        child.layout[pos[crossAxis]] += leadingCrossDim;
      } else {
        if (isPosDefined(child, leading[crossAxis])) {
          child.layout[pos[crossAxis]] = getPosition(child, leading[crossAxis]) +
            getBorder(node, leading[crossAxis]) +
            getMargin(child, leading[crossAxis]);
        } else {
          child.layout[pos[crossAxis]] += getPaddingAndBorder(node, leading[crossAxis]);
        }
      }
    }

    node.layout[leading[mainAxis]] += getMargin(node, leading[mainAxis]) +
      getRelativePosition(node, mainAxis);
    node.layout[leading[crossAxis]] += getMargin(node, leading[crossAxis]) +
      getRelativePosition(node, crossAxis);
  }

  var fn = function(node) {
    fillNodes(node);
    layoutNode(node);
    return extractNodes(node);
  };
  fn.layoutNode = layoutNode;
  return fn;
})();

<commit_msg>remove a local variable<commit_after>
var computeLayout = (function() {

  function fillNodes(node) {
    node.layout = {
      width: undefined,
      height: undefined,
      top: 0,
      left: 0
    };
    if (!node.style) {
      node.style = {};
    }
    if (!node.children) {
      node.children = [];
    }
    node.children.forEach(fillNodes);
  }

  function extractNodes(node) {
    var layout = node.layout;
    delete node.layout;
    if (node.children.length > 0) {
      layout.children = node.children.map(extractNodes);
    } else {
      delete node.children;
    }
    return layout;
  }

  function capitalizeFirst(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }

  function getSpacing(node, type, suffix, location) {
    var key = type + capitalizeFirst(location) + suffix;
    if (key in node.style) {
      return node.style[key];
    }

    key = type + suffix;
    if (key in node.style) {
      return node.style[key];
    }

    return 0;
  }

  function getPositiveSpacing(node, type, suffix, location) {
    var key = type + capitalizeFirst(location) + suffix;
    if (key in node.style && node.style[key] >= 0) {
      return node.style[key];
    }

    key = type + suffix;
    if (key in node.style && node.style[key] >= 0) {
      return node.style[key];
    }

    return 0;
  }

  function isUndefined(value) {
    return value === undefined;
  }

  function getMargin(node, location) {
    return getSpacing(node, 'margin', '', location);
  }

  function getPadding(node, location) {
    return getPositiveSpacing(node, 'padding', '', location);
  }

  function getBorder(node, location) {
    return getPositiveSpacing(node, 'border', 'Width', location);
  }

  function getPaddingAndBorder(node, location) {
    return getPadding(node, location) + getBorder(node, location);
  }

  function getMarginAxis(node, axis) {
    return getMargin(node, leading[axis]) + getMargin(node, trailing[axis]);
  }

  function getPaddingAndBorderAxis(node, axis) {
    return getPaddingAndBorder(node, leading[axis]) + getPaddingAndBorder(node, trailing[axis]);
  }

  function getJustifyContent(node) {
    if ('justifyContent' in node.style) {
      return node.style.justifyContent;
    }
    return 'flex-start';
  }

  function getAlignItem(node, child) {
    if ('alignSelf' in child.style) {
      return child.style.alignSelf;
    }
    if ('alignItems' in node.style) {
      return node.style.alignItems;
    }
    return 'flex-start';
  }

  function getFlexDirection(node) {
    if ('flexDirection' in node.style) {
      return node.style.flexDirection;
    }
    return 'column';
  }

  function getPositionType(node) {
    if ('position' in node.style) {
      return node.style.position;
    }
    return 'relative';
  }

  function getFlex(node) {
    return node.style.flex === 1;
  }

  function getDimWithMargin(node, axis) {
    return node.layout[dim[axis]] + getMarginAxis(node, axis);
  }

  function isDimDefined(node, axis) {
    return !isUndefined(node.style[dim[axis]]) && node.style[dim[axis]] >= 0;
  }

  function isPosDefined(node, pos) {
    return !isUndefined(node.style[pos]);
  }

  function getPosition(node, pos) {
    if (pos in node.style) {
      return node.style[pos];
    }
    return 0;
  }

  // If both left and right are defined, then use left. Otherwise return
  // +left or -right depending on which is defined.
  function getRelativePosition(node, axis) {
    if (leading[axis] in node.style) {
      return getPosition(node, leading[axis]);
    }
    return -getPosition(node, trailing[axis]);
  }

  var leading = {
    row: 'left',
    column: 'top'
  };
  var trailing = {
    row: 'right',
    column: 'bottom'
  };
  var pos = {
    row: 'left',
    column: 'top'
  };
  var dim = {
    row: 'width',
    column: 'height'
  };

  function fmaxf(a, b) {
    if (a > b) {
      return a;
    }
    return b;
  }

  var CSS_FLEX_DIRECTION_ROW = 'row';
  var CSS_FLEX_DIRECTION_COLUMN = 'column';

  var CSS_JUSTIFY_FLEX_START = 'flex-start';
  var CSS_JUSTIFY_CENTER = 'center';
  var CSS_JUSTIFY_FLEX_END = 'flex-end';
  var CSS_JUSTIFY_SPACE_BETWEEN = 'space-between';
  var CSS_JUSTIFY_SPACE_AROUND = 'space-around';

  var CSS_ALIGN_FLEX_START = 'flex-start';
  var CSS_ALIGN_CENTER = 'center';
  var CSS_ALIGN_FLEX_END = 'flex-end';
  var CSS_ALIGN_STRETCH = 'stretch';

  var CSS_POSITION_RELATIVE = 'relative';
  var CSS_POSITION_ABSOLUTE = 'absolute';

  function layoutNode(node) {
    var/*css_flex_direction_t*/ mainAxis = getFlexDirection(node);
    var/*css_flex_direction_t*/ crossAxis = mainAxis === CSS_FLEX_DIRECTION_ROW ?
      CSS_FLEX_DIRECTION_COLUMN :
      CSS_FLEX_DIRECTION_ROW;

    if (isUndefined(node.layout[dim[mainAxis]]) && isDimDefined(node, mainAxis)) {
      node.layout[dim[mainAxis]] = fmaxf(
        node.style[dim[mainAxis]],
        getPaddingAndBorderAxis(node, mainAxis)
      );
    }

    if (isUndefined(node.layout[dim[crossAxis]]) && isDimDefined(node, crossAxis)) {
      node.layout[dim[crossAxis]] = fmaxf(
        node.style[dim[crossAxis]],
        getPaddingAndBorderAxis(node, crossAxis)
      );
    }

    var/*float*/ mainContentDim = 0;
    var/*int*/ flexibleChildrenCount = 0;
    var/*int*/ absoluteChildrenCount = 0;
    for (var/*int*/ i = 0; i < node.children.length; ++i) {
      var/*css_node_t**/ child = node.children[i];
      if (isUndefined(node.layout[dim[mainAxis]]) ||
          getPositionType(child) === CSS_POSITION_ABSOLUTE ||
          !getFlex(child)) {
        layoutNode(child);
        if (getPositionType(child) === CSS_POSITION_RELATIVE) {
          mainContentDim += getDimWithMargin(child, mainAxis);
        } else {
          absoluteChildrenCount++;
        }
      } else {
        flexibleChildrenCount++;
        mainContentDim += getPaddingAndBorderAxis(child, mainAxis) + getMarginAxis(child, mainAxis);
      }
    }

    var/*float*/ leadingMainDim = 0;
    var/*float*/ betweenMainDim = 0;
    if (!isUndefined(node.layout[dim[mainAxis]])) {
      var/*float*/ remainingMainDim = node.layout[dim[mainAxis]] -
        getPaddingAndBorderAxis(node, mainAxis) -
        mainContentDim;

      if (flexibleChildrenCount) {
        var/*float*/ flexibleMainDim = remainingMainDim / flexibleChildrenCount;
        if (flexibleMainDim < 0) {
          flexibleMainDim = 0;
        }
        for (var/*int*/ i = 0; i < node.children.length; ++i) {
          var/*css_node_t**/ child = node.children[i];
          if (getPositionType(child) === CSS_POSITION_RELATIVE && getFlex(child)) {
            child.layout[dim[mainAxis]] = flexibleMainDim + getPaddingAndBorderAxis(child, mainAxis);
            layoutNode(child);
          }
        }
      } else {
        var/*css_justify_t*/ justifyContent = getJustifyContent(node);
        if (justifyContent === CSS_JUSTIFY_FLEX_START) {
          // Do nothing
        } else if (justifyContent === CSS_JUSTIFY_CENTER) {
          leadingMainDim = remainingMainDim / 2;
        } else if (justifyContent === CSS_JUSTIFY_FLEX_END) {
          leadingMainDim = remainingMainDim;
        } else if (justifyContent === CSS_JUSTIFY_SPACE_BETWEEN) {
          betweenMainDim = remainingMainDim / (node.children.length - absoluteChildrenCount - 1);
        } else if (justifyContent === CSS_JUSTIFY_SPACE_AROUND) {
          betweenMainDim = remainingMainDim / (node.children.length - absoluteChildrenCount);
          leadingMainDim = betweenMainDim / 2;
        }
      }
    }

    var/*float*/ crossDim = 0;
    var/*float*/ mainPos = getPaddingAndBorder(node, leading[mainAxis]) + leadingMainDim;
    for (var/*int*/ i = 0; i < node.children.length; ++i) {
      var/*css_node_t**/ child = node.children[i];
      if (getPositionType(child) === CSS_POSITION_ABSOLUTE && isPosDefined(child, leading[mainAxis])) {
        child.layout[pos[mainAxis]] = getPosition(child, leading[mainAxis]) +
          getBorder(node, leading[mainAxis]) +
          getMargin(child, leading[mainAxis]);
      } else {
        child.layout[pos[mainAxis]] += mainPos;
      }
      if (getPositionType(child) === CSS_POSITION_RELATIVE) {
        mainPos += getDimWithMargin(child, mainAxis) + betweenMainDim;

        if (!isUndefined(child.layout[dim[crossAxis]])) {
          var/*float*/ childCrossDim = getDimWithMargin(child, crossAxis);
          if (childCrossDim > crossDim) {
            crossDim = childCrossDim;
          }
        }
      }
    }

    mainPos += getPaddingAndBorder(node, trailing[mainAxis]);
    crossDim += getPaddingAndBorderAxis(node, crossAxis);

    if (isUndefined(node.layout[dim[mainAxis]]) && !isDimDefined(node, mainAxis)) {
      node.layout[dim[mainAxis]] = fmaxf(mainPos, getPaddingAndBorderAxis(node, mainAxis));
    }
    if (isUndefined(node.layout[dim[crossAxis]])) {
      node.layout[dim[crossAxis]] = fmaxf(crossDim, getPaddingAndBorderAxis(node, crossAxis));
    }

    for (var/*int*/ i = 0; i < node.children.length; ++i) {
      var/*css_node_t**/ child = node.children[i];

      if (getPositionType(child) === CSS_POSITION_RELATIVE) {
        var/*css_align_t*/ alignItem = getAlignItem(node, child);
        var/*float*/ remainingCrossDim = node.layout[dim[crossAxis]] -
          getDimWithMargin(child, crossAxis) -
          getPaddingAndBorderAxis(node, crossAxis);

        var/*float*/ leadingCrossDim = getPaddingAndBorder(node, leading[crossAxis]);
        if (alignItem === CSS_ALIGN_FLEX_START) {
          // Do nothing
        } else if (alignItem === CSS_ALIGN_CENTER) {
          leadingCrossDim += remainingCrossDim / 2;
        } else if (alignItem === CSS_ALIGN_FLEX_END) {
          leadingCrossDim += remainingCrossDim;
        } else if (alignItem === CSS_ALIGN_STRETCH) {
          if (!isDimDefined(child, crossAxis)) {
            child.layout[dim[crossAxis]] = fmaxf(
              node.layout[dim[crossAxis]] -
                getPaddingAndBorderAxis(node, crossAxis) -
                getMarginAxis(child, crossAxis),
              getPaddingAndBorderAxis(child, crossAxis)
            );
          }
        }
        child.layout[pos[crossAxis]] += leadingCrossDim;
      } else {
        if (isPosDefined(child, leading[crossAxis])) {
          child.layout[pos[crossAxis]] = getPosition(child, leading[crossAxis]) +
            getBorder(node, leading[crossAxis]) +
            getMargin(child, leading[crossAxis]);
        } else {
          child.layout[pos[crossAxis]] += getPaddingAndBorder(node, leading[crossAxis]);
        }
      }
    }

    node.layout[leading[mainAxis]] += getMargin(node, leading[mainAxis]) +
      getRelativePosition(node, mainAxis);
    node.layout[leading[crossAxis]] += getMargin(node, leading[crossAxis]) +
      getRelativePosition(node, crossAxis);
  }

  var fn = function(node) {
    fillNodes(node);
    layoutNode(node);
    return extractNodes(node);
  };
  fn.layoutNode = layoutNode;
  return fn;
})();

<|endoftext|>


<commit_before>/**
 * `modules/analytics` data store: setup-flow tests.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { createRegistry } from '@wordpress/data';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import { MODULES_ANALYTICS } from './constants';
import { createTestRegistry, unsubscribeFromAll } from 'tests/js/utils';
import * as modulesAnalytics from '../';
import { MODULES_ANALYTICS_4 } from '../../analytics-4/datastore/constants';

const accountID = 'pub-12345678';

const populateAnalyticsDatastore = ( registry ) => {
	registry.dispatch( MODULES_ANALYTICS ).receiveGetProperties(
		[
			{
				// eslint-disable-next-line sitekit/acronym-case
				accountId: accountID,
				id: 'UA-151753095-1',
				name: 'rwh',
			},
			{
				// eslint-disable-next-line sitekit/acronym-case
				accountId: accountID,
				id: 'UA-151753095-1',
				name: 'troubled-tipped.example.com',
			},

		],
		{ accountID }
	);
};

const populateAnalytics4Datastore = ( registry ) => {
	registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetProperties( [
		{
			_id: '1000',
			_accountID: '100',
			name: 'properties/1000',
			createTime: '2014-10-02T15:01:23Z',
			updateTime: '2014-10-02T15:01:23Z',
			parent: 'accounts/100',
			displayName: 'Test GA4 Property',
			industryCategory: 'TECHNOLOGY',
			timeZone: 'America/Los_Angeles',
			currencyCode: 'USD',
			deleted: false,
		},
	],
	{ accountID },
	);
	registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetWebDataStreams(
		[
			{
				_id: '2000',
				_propertyID: '1000',
				name: 'properties/1000/webDataStreams/2000',
				// eslint-disable-next-line sitekit/acronym-case
				measurementId: '1A2BCD345E',
				// eslint-disable-next-line sitekit/acronym-case
				firebaseAppId: '',
				createTime: '2014-10-02T15:01:23Z',
				updateTime: '2014-10-02T15:01:23Z',
				defaultUri: 'http://example.com',
				displayName: 'Test GA4 WebDataStream',
			},
		],
		{ propertyID: 'foobar' }
	);
};

describe( 'modules/analytics setup-flow', () => {
	let registry;

	beforeAll( () => {
		API.setUsingCache( false );
	} );

	afterAll( () => {
		API.setUsingCache( true );
	} );

	afterEach( () => {
		unsubscribeFromAll( registry );
	} );

	describe( 'selectors', () => {
		describe( 'getSetupFlowMode', () => {
			it( 'returns "legacy" if the modules/analytics-4 store is not available ', async () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				// just for this test create new registry with only this module
				const newRegistry = createRegistry();

				modulesAnalytics.registerStore( newRegistry );

				registry = newRegistry;
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( 'legacy' );
			} );

			it( 'should return "legacy" if isAdminAPIWorking() returns false', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				registry.dispatch( MODULES_ANALYTICS_4 ).receiveError(
					new Error( 'foo' ), 'getProperties', [ 'foo', 'bar' ]
				);

				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( false );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( 'legacy' );
			} );

			it( 'should return undefined if isAdminAPIWorking() returns undefined ', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( undefined );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( undefined );
			} );

			it( 'should return undefined if settings are still loading', () => {
				fetchMock.get(
					/^\/google-site-kit\/v1\/modules\/analytics\/data\/settings/,
					{
						body: {
							accountID: 'pub-12345678',
							clientID: 'ca-pub-12345678',
							useSnippet: true,
						},
						status: 200,
					}
				);

				registry = createTestRegistry();

				populateAnalytics4Datastore( registry );

				expect( registry.select( MODULES_ANALYTICS ).getSettings() ).toBe( undefined );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( undefined );
			} );

			it( 'should return "ua" if there is no account selected', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				expect( registry.select( MODULES_ANALYTICS ).getAccountID( accountID ) ).toBe( undefined );

				populateAnalytics4Datastore( registry );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( 'ua' );
			} );

			it( 'should return undefined if selected account returns undefined from GA4 getProperties selector', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				registry.dispatch( MODULES_ANALYTICS ).setAccountID( accountID );
				populateAnalyticsDatastore( registry );

				expect( registry.select( MODULES_ANALYTICS ).getProperties() ).toBe( undefined );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( undefined );
			} );

			it( 'should return "ua" if selected account returns an empty array from GA4 getProperties selector', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				registry.dispatch( MODULES_ANALYTICS ).setAccountID( accountID );
				populateAnalyticsDatastore( registry );

				// For isAdminAPIWorking() to return true:
				// "The state['properties'] object has at least one account with a non-empty array of properties;"
				// See: https://github.com/google/site-kit-wp/issues/3169
				registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetProperties( [
					{
						_id: '1000',
						_accountID: '100',
						name: 'properties/1000',
						createTime: '2014-10-02T15:01:23Z',
						updateTime: '2014-10-02T15:01:23Z',
						parent: 'accounts/100',
						displayName: 'Test GA4 Property',
						industryCategory: 'TECHNOLOGY',
						timeZone: 'America/Los_Angeles',
						currencyCode: 'USD',
						deleted: false,
					},
				],
				{ accountID: 'another-different-id' },
				);

				//  Receive empty properties list to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetProperties(
					[],
					{ accountID },
				);
				registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetWebDataStreams(
					[
						{
							_id: '2000',
							_propertyID: '1000',
							name: 'properties/1000/webDataStreams/2000',
							// eslint-disable-next-line sitekit/acronym-case
							measurementId: '1A2BCD345E',
							// eslint-disable-next-line sitekit/acronym-case
							firebaseAppId: '',
							createTime: '2014-10-02T15:01:23Z',
							updateTime: '2014-10-02T15:01:23Z',
							defaultUri: 'http://example.com',
							displayName: 'Test GA4 WebDataStream',
						},
					],
					{ propertyID: 'foobar' }
				);

				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( true );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( 'ua' );
			} );

			it( 'should return undefined if selected account returns an empty array from UA getProperties selector', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				registry.dispatch( MODULES_ANALYTICS ).setAccountID( accountID );

				registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetWebDataStreams(
					[
						{
							_id: '2000',
							_propertyID: '1000',
							name: 'properties/1000/webDataStreams/2000',
							// eslint-disable-next-line sitekit/acronym-case
							measurementId: '1A2BCD345E',
							// eslint-disable-next-line sitekit/acronym-case
							firebaseAppId: '',
							createTime: '2014-10-02T15:01:23Z',
							updateTime: '2014-10-02T15:01:23Z',
							defaultUri: 'http://example.com',
							displayName: 'Test GA4 WebDataStream',
						},
					],
					{ propertyID: 'foobar' }
				);

				// Need to dispatch empty UA properties so has loaded
				registry.dispatch( MODULES_ANALYTICS ).receiveGetProperties(
					[],
					{ accountID },
				);

				fetchMock.get(
					/^\/google-site-kit\/v1\/modules\/analytics-4\/data\/properties/,
					{
						body: [],
						status: 200,
					}
				);

				expect( registry.select( MODULES_ANALYTICS_4 ).getProperties( accountID ) ).toBe( undefined );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( undefined );
			} );

			it( 'should return "ga4" if selected account returns an empty array from UA getProperties selector', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				registry.dispatch( MODULES_ANALYTICS ).setAccountID( accountID );
				populateAnalytics4Datastore( registry );

				// Need to dispatch empty properties so has loaded
				registry.dispatch( MODULES_ANALYTICS ).receiveGetProperties(
					[],
					{ accountID },
				);

				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( true );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( 'ga4' );
			} );

			it( 'should return "ga4-transitional" if both GA4 and UA properties are found for an account', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				registry.dispatch( MODULES_ANALYTICS ).setAccountID( accountID );
				populateAnalytics4Datastore( registry );
				populateAnalyticsDatastore( registry );

				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( true );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( 'ga4-transitional' );
			} );
		} );
	} );
} );
<commit_msg>Fix test to properly test for empty UA properties array.<commit_after>/**
 * `modules/analytics` data store: setup-flow tests.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { createRegistry } from '@wordpress/data';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import { MODULES_ANALYTICS } from './constants';
import { createTestRegistry, unsubscribeFromAll } from 'tests/js/utils';
import * as modulesAnalytics from '../';
import { MODULES_ANALYTICS_4 } from '../../analytics-4/datastore/constants';

const accountID = 'pub-12345678';

const populateAnalyticsDatastore = ( registry ) => {
	registry.dispatch( MODULES_ANALYTICS ).receiveGetProperties(
		[
			{
				// eslint-disable-next-line sitekit/acronym-case
				accountId: accountID,
				id: 'UA-151753095-1',
				name: 'rwh',
			},
			{
				// eslint-disable-next-line sitekit/acronym-case
				accountId: accountID,
				id: 'UA-151753095-1',
				name: 'troubled-tipped.example.com',
			},

		],
		{ accountID }
	);
};

const populateAnalytics4Datastore = ( registry ) => {
	registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetProperties( [
		{
			_id: '1000',
			_accountID: '100',
			name: 'properties/1000',
			createTime: '2014-10-02T15:01:23Z',
			updateTime: '2014-10-02T15:01:23Z',
			parent: 'accounts/100',
			displayName: 'Test GA4 Property',
			industryCategory: 'TECHNOLOGY',
			timeZone: 'America/Los_Angeles',
			currencyCode: 'USD',
			deleted: false,
		},
	],
	{ accountID },
	);
	registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetWebDataStreams(
		[
			{
				_id: '2000',
				_propertyID: '1000',
				name: 'properties/1000/webDataStreams/2000',
				// eslint-disable-next-line sitekit/acronym-case
				measurementId: '1A2BCD345E',
				// eslint-disable-next-line sitekit/acronym-case
				firebaseAppId: '',
				createTime: '2014-10-02T15:01:23Z',
				updateTime: '2014-10-02T15:01:23Z',
				defaultUri: 'http://example.com',
				displayName: 'Test GA4 WebDataStream',
			},
		],
		{ propertyID: 'foobar' }
	);
};

describe( 'modules/analytics setup-flow', () => {
	let registry;

	beforeAll( () => {
		API.setUsingCache( false );
	} );

	afterAll( () => {
		API.setUsingCache( true );
	} );

	afterEach( () => {
		unsubscribeFromAll( registry );
	} );

	describe( 'selectors', () => {
		describe( 'getSetupFlowMode', () => {
			it( 'returns "legacy" if the modules/analytics-4 store is not available ', async () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				// just for this test create new registry with only this module
				const newRegistry = createRegistry();

				modulesAnalytics.registerStore( newRegistry );

				registry = newRegistry;
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( 'legacy' );
			} );

			it( 'should return "legacy" if isAdminAPIWorking() returns false', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				registry.dispatch( MODULES_ANALYTICS_4 ).receiveError(
					new Error( 'foo' ), 'getProperties', [ 'foo', 'bar' ]
				);

				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( false );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( 'legacy' );
			} );

			it( 'should return undefined if isAdminAPIWorking() returns undefined ', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( undefined );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( undefined );
			} );

			it( 'should return undefined if settings are still loading', () => {
				fetchMock.get(
					/^\/google-site-kit\/v1\/modules\/analytics\/data\/settings/,
					{
						body: {
							accountID: 'pub-12345678',
							clientID: 'ca-pub-12345678',
							useSnippet: true,
						},
						status: 200,
					}
				);

				registry = createTestRegistry();

				populateAnalytics4Datastore( registry );
				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( true );

				expect( registry.select( MODULES_ANALYTICS ).getSettings() ).toBe( undefined );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( undefined );
			} );

			it( 'should return "ua" if there is no account selected', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				expect( registry.select( MODULES_ANALYTICS ).getAccountID( accountID ) ).toBe( undefined );

				populateAnalytics4Datastore( registry );
				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( true );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( 'ua' );
			} );

			it( 'should return undefined if selected account returns undefined from GA4 getProperties selector', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				registry.dispatch( MODULES_ANALYTICS ).setAccountID( accountID );
				populateAnalyticsDatastore( registry );

				expect( registry.select( MODULES_ANALYTICS ).getProperties() ).toBe( undefined );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( undefined );
			} );

			it( 'should return "ua" if selected account returns an empty array from GA4 getProperties selector', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				registry.dispatch( MODULES_ANALYTICS ).setAccountID( accountID );
				populateAnalyticsDatastore( registry );

				// For isAdminAPIWorking() to return true:
				// "The state['properties'] object has at least one account with a non-empty array of properties;"
				// See: https://github.com/google/site-kit-wp/issues/3169
				registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetProperties( [
					{
						_id: '1000',
						_accountID: '100',
						name: 'properties/1000',
						createTime: '2014-10-02T15:01:23Z',
						updateTime: '2014-10-02T15:01:23Z',
						parent: 'accounts/100',
						displayName: 'Test GA4 Property',
						industryCategory: 'TECHNOLOGY',
						timeZone: 'America/Los_Angeles',
						currencyCode: 'USD',
						deleted: false,
					},
				],
				// This is a different accountID
				{ accountID: 'bar-1234567' },
				);

				//  Receive empty properties list to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetProperties(
					[],
					{ accountID },
				);
				registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetWebDataStreams(
					[
						{
							_id: '2000',
							_propertyID: '1000',
							name: 'properties/1000/webDataStreams/2000',
							// eslint-disable-next-line sitekit/acronym-case
							measurementId: '1A2BCD345E',
							// eslint-disable-next-line sitekit/acronym-case
							firebaseAppId: '',
							createTime: '2014-10-02T15:01:23Z',
							updateTime: '2014-10-02T15:01:23Z',
							defaultUri: 'http://example.com',
							displayName: 'Test GA4 WebDataStream',
						},
					],
					{ propertyID: 'foobar' }
				);

				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( true );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( 'ua' );
			} );

			it( 'should return undefined if selected account returns undefined from UA getProperties selector', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				registry.dispatch( MODULES_ANALYTICS ).setAccountID( accountID );

				populateAnalytics4Datastore( registry );

				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( true );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( undefined );
			} );

			it( 'should return "ga4" if selected account returns an empty array from UA getProperties selector', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				registry.dispatch( MODULES_ANALYTICS ).setAccountID( accountID );
				populateAnalytics4Datastore( registry );

				// Need to dispatch empty properties so has loaded
				registry.dispatch( MODULES_ANALYTICS ).receiveGetProperties(
					[],
					{ accountID },
				);

				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( true );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( 'ga4' );
			} );

			it( 'should return "ga4-transitional" if both GA4 and UA properties are found for an account', () => {
				registry = createTestRegistry();
				// Receive empty settings to prevent unexpected fetch by resolver.
				registry.dispatch( MODULES_ANALYTICS ).receiveGetSettings( {} );
				registry.dispatch( MODULES_ANALYTICS ).setAccountID( accountID );
				populateAnalytics4Datastore( registry );
				populateAnalyticsDatastore( registry );

				expect( registry.select( MODULES_ANALYTICS_4 ).isAdminAPIWorking() ).toBe( true );

				expect( registry.select( MODULES_ANALYTICS ).getSetupFlowMode() ).toBe( 'ga4-transitional' );
			} );
		} );
	} );
} );
<|endoftext|>


<commit_before>(function() {
	exports.parseSingleProgram = function(item) {
		try {
			var fullTitle = (item.getElementsByTagName('title').item(0).text).replace(/\n/gi, ' ').replace('CANAL+', 'Canal+').replace('ARTE', 'Arte');
			var desc = strip_tags(((item.getElementsByTagName('description').item(0).text).replace(/\n/gi, ' ').replace(' ', '').replace('[...]', '').split('/>'))[1], null);
			var category = 'N/A';

			var descParts = desc.split('. ');

			if(descParts[1] != null) {
				category = Utils.capitalize(descParts.shift());
				desc = descParts.join('. ');
			}

			var titleComps = fullTitle.match(/(.*) : ([0-9]{2}h[0-9]{2}) (.*)/);

			return {
				title: titleComps[3],
				description: desc,
				url: (item.getElementsByTagName('link').item(0).text).replace(/\n/gi, ' '),
				startTime: titleComps[2],
				channelString: titleComps[1],
				channelID: Utils.getChannelID(titleComps[1]),
				category: category
			};
		} catch(e) {
			return null;
		}
	}

	exports.getAllRows = function(itemList, callback) {
		var lastChannelID;

		for(var i = 0; i < itemList.length; i++) {
			var progData = exports.parseSingleProgram(itemList.item(i));

			var row = Ti.UI.createTableViewRow({
				hasChild: true,
				height: Ti.UI.SIZE,
				selectedBackgroundColor: '#565656',
				searchFilter: progData.title + ' ' + progData.channelString,
				data: progData
			});

			if(row != null) {
				if(lastChannelID != row.data.channelID) {
					var header = Ti.UI.createTableViewRow({
						height: 30,
						selectionStyle: Ti.UI.iPhone.TableViewCellSelectionStyle.NONE,
						backgroundColor: '#d4d4d4',
						backgroundGradient: {
							type: 'linear',
							colors: [{
								color: '#d4d4d4',
								position: 0.0
							}, {
								color: '#c4c4c4',
								position: 0.50
							}, {
								color: '#b4b4b4',
								position: 1.0
							}]
						},
						borderColor: 'darkGray',
						borderRadius: 1,
						isHeader: true
					});

					var img = Ti.UI.createImageView({
						image: '/img/logo/' + row.data.channelID + '.png',
						defaultImage: '/img/default_epg.png',
						height: 27,
						width: 27,
						left: 10
					});

					var lbl_channel = Ti.UI.createLabel({
						text: row.data.channelString,
						left: 50,
						top: 1,
						color: '#484848',
						font: {
							fontSize: 15,
							fontFamily: 'Helvetica Neue',
							fontWeight: 'bold'
						},
						shadowColor: 'white',
						shadowOffset: {
							x: 0,
							y: 1
						},
						height: Ti.UI.FILL
					});

					lastChannelID = row.data.channelID;
					header.add(img);
					header.add(lbl_channel);

					//append header
					callback(header);
				}

				var row_time = Ti.UI.createLabel({
					text: row.data.startTime,
					color: '#000',
					textAlign: 'left',
					left: 7,
					height: Ti.UI.SIZE,
					width: Ti.UI.SIZE,
					top: 8,
					bottom: 8,
					font: {
						fontWeight: 'bold',
						fontSize: 16
					},
					highlightedColor: 'white'
				});

				var row_title = Ti.UI.createLabel({
					text: row.data.title,
					color: '#000',
					textAlign: 'left',
					left: 60,
					height: Ti.UI.SIZE,
					width: Ti.UI.SIZE,
					top: 7,
					bottom: 8,
					font: {
						fontSize: 15
					},
					highlightedColor: 'white'
				});

				row.add(row_time);
				row.add(row_title);

				callback(row);
			}
		}
	}
})();
<commit_msg>Improve gradients on epg<commit_after>(function() {
	exports.parseSingleProgram = function(item) {
		try {
			var fullTitle = (item.getElementsByTagName('title').item(0).text).replace(/\n/gi, ' ').replace('CANAL+', 'Canal+').replace('ARTE', 'Arte');
			var desc = strip_tags(((item.getElementsByTagName('description').item(0).text).replace(/\n/gi, ' ').replace(' ', '').replace('[...]', '').split('/>'))[1], null);
			var category = 'N/A';

			var descParts = desc.split('. ');

			if(descParts[1] != null) {
				category = Utils.capitalize(descParts.shift());
				desc = descParts.join('. ');
			}

			var titleComps = fullTitle.match(/(.*) : ([0-9]{2}h[0-9]{2}) (.*)/);

			return {
				title: titleComps[3],
				description: desc,
				url: (item.getElementsByTagName('link').item(0).text).replace(/\n/gi, ' '),
				startTime: titleComps[2],
				channelString: titleComps[1],
				channelID: Utils.getChannelID(titleComps[1]),
				category: category
			};
		} catch(e) {
			return null;
		}
	}

	exports.getAllRows = function(itemList, callback) {
		var lastChannelID;

		for(var i = 0; i < itemList.length; i++) {
			var progData = exports.parseSingleProgram(itemList.item(i));

			var row = Ti.UI.createTableViewRow({
				hasChild: true,
				height: Ti.UI.SIZE,
				selectedBackgroundColor: '#565656',
				searchFilter: progData.title + ' ' + progData.channelString,
				data: progData
			});

			if(row != null) {
				if(lastChannelID != row.data.channelID) {
					var header = Ti.UI.createTableViewRow({
						height: 30,
						selectionStyle: Ti.UI.iPhone.TableViewCellSelectionStyle.NONE,
						backgroundColor: '#d0d0d0',
						borderColor: 'darkGray',
						borderRadius: 1,
						isHeader: true
					});

					var img = Ti.UI.createImageView({
						image: '/img/logo/' + row.data.channelID + '.png',
						defaultImage: '/img/default_epg.png',
						height: 27,
						width: 27,
						left: 10
					});

					var lbl_channel = Ti.UI.createLabel({
						text: row.data.channelString,
						left: 50,
						top: 1,
						color: '#606060',
						font: {
							fontSize: 15,
							fontFamily: 'Helvetica Neue',
							fontWeight: 'bold'
						},
						height: Ti.UI.FILL
					});

					lastChannelID = row.data.channelID;
					header.add(img);
					header.add(lbl_channel);

					//append header
					callback(header);
				}

				var row_time = Ti.UI.createLabel({
					text: row.data.startTime,
					color: '#000',
					textAlign: 'left',
					left: 7,
					height: Ti.UI.SIZE,
					width: Ti.UI.SIZE,
					top: 8,
					bottom: 8,
					font: {
						fontWeight: 'bold',
						fontSize: 16
					},
					highlightedColor: 'white'
				});

				var row_title = Ti.UI.createLabel({
					text: row.data.title,
					color: '#000',
					textAlign: 'left',
					left: 60,
					height: Ti.UI.SIZE,
					width: Ti.UI.SIZE,
					top: 7,
					bottom: 8,
					font: {
						fontSize: 15
					},
					highlightedColor: 'white'
				});

				row.add(row_time);
				row.add(row_title);

				callback(row);
			}
		}
	}
})();
<|endoftext|>