אני מנסה ליצור דו”ח Extent Report בעברית ויוצא ג’יבריש. מישהו יודע מה הבעיה? זאת היתה השאלה שלי בפייסבוק. התשובה הראשונה שקיבלתי – למה בעברית?

ברוב המקרים, אכן נעדיף לעבוד באנגלית. יחד עם זאת, יש מקרים בהם, מה לעשות, אנחנו צריכים לייצר דו”ח על פי דרישה. עבורי הדרישה הפעם היתה לייצר דו”ח מנהלים בעברית.

בבלוג הזה אציג את הפתרון שלי לבניית דו”חות Extent Reports בעברית. העקרון הוא זהה גם לקבצי הרצה אחרים, או לקבצים בכלל שצריכים להציג עברית ונערכים ב- Java.

מחפשים פתרון ואין לכם כח לקרוא? הנה סיכום של הבלוג עם 2 הפתרונות:

א. הגדירו בתוך קובץ הקונפיגורציה של Extent Report שה- encoding  שלו הוא windows-1255 (או בצורה גנרית, להגדיר ב- HTML שה – encoding  של הקובץ הוא 1255. הפתרון הזה עובד ותקין, אבל אני פחות ממליץ עליו.

ב. לייצר דו”ח עם מחרוזות באיזו שפה שאתם רוצים, ובסוף, לאחר היצירה של דו”ח HTML לבצע המרה של כל הקובץ ל- UTF-8. זה הפתרון המועדף עלי, וכתבתי פונקציית המרה. הפונקציה שלי נמצאת בסוף הפוסט.

רוצים לקרוא עוד קצת? יללה

הקונפיגורציה: פרויקט Java maven עם Selenium ו- Junit 5 שמשתמש ב- ExtentReport גרסה 3

הקדמה:

כדי לייצר דו”ח ב- ExtentReport ו- Junit, הקוד הבא הוא דוגמא בסיסית:

@Test
public void extentReportDemo() {

    // (1) - Create report objects
    String reportName = "./target/demo_report.html";
    ExtentHtmlReporter reporter = new ExtentHtmlReporter(reportName);
    ExtentReports report = new ExtentReports();
    ExtentTest test = report.createTest("My Test");

    report.attachReporter(reporter);

    // (2) - Use report
    report.flush();

    test.pass("Yay... We passed");

    // (3) - Generate the report
    report.flush();
}

(1) זהו שלב ההכנות. מגדירים את הנתיב בו נשמור ואת שם הדו”ח.

(2) יוצרים טסט חדש בדו”ח ומזינים אליו נתונים
(3) לאחר סיום כתיבת הנתונים לדו”ח, מייצרים ממנו דו”ח HTML

וככה זה נראה:

ועכשיו עם שינוי קטן:

test.pass("עברנו בהצלחה כל הכבוד");

נריץ שוב את הדו”ח ופתאום נראה:

אוקיי, מה קרה פה (רמז – encoding)?

כדי להבין מה קרה, חשוב להבין איך מחשב מציג אותיות (במלים אחרות, מה זה Encoding).

מכיוון שמחשב הוא חיה בינארית, ויודע לעבוד עם מספרים בלבד שמתורגמים ל 0 ו – 1, כל אות בעולם מיוצגת על ידי מס’. התהליך של תרגום אות למספר נקרא encoding והתהליך של תרגום מספר לאות נקרא decoding. זאת אומרת, שכדי להבין נכון אות צריך מפה שתמיר לנו את האות למס’ הייחודי שלה ולהפך. עד פה סבבה, אז מה הבעיה? הבעיה היא שיש כמה “מפות” כאלה, ואות שמיוצגת במפה אחת על ידי מספר כלשהו, במפה אחרת תהיה מיוצגת על ידי מספר אחר לגמרי. לדוגמא, אם נקח “מפה” (קידוד) שנקרא ASCII, הקידוד של האות א’ יהיה 128, בעוד בקידוד אחר windows-1255 הקידוד לאותה האות יהיה 224, וב- UTF8 הוא יהיה 55,184.

בעצם מה שקרה לנו הוא שכתבנו את המשפט “עברנו בהצלחה כל הכבוד” בקידוד windows-1255 לדו”ח שה- decoder שלו מתבצע ב- UTF8. בגלל זה זה לא עבד.

למה זה קרה? כי כאשר הוספנו ב- Windows את השפה העברית (באיזור Region & Language בהגדרות), Windows התקין עבורנו את ה- encoder שלו – windows-1255 ומאותו הרגע, כל מה שנכתוב בעברית במחשב יקודד ב- windows-1255.

ואם נקודד את הטקסט ב- UFF8 ונכתוב אותו כך לדו”ח, זה יעזור? לדוגמא ב- Java זה ייראה כך:

public String toUTF8(String strIn) throws UnsupportedEncodingException {
    byte[] b =strIn.getBytes("UTF-8");
    return new String(b, "UTF-8");
}

ואז בזמן כתיבת הדו”ח נכתוב:

test.pass(toUTF8("עברנו בהצלחה כל הכבוד"));

התשובה היא לא!

במחשב כאשר פותחים את קובץ לכתיבה, קידוד הכתיבה מתבצע בשפה הלוקלית שלו. ולכן כל הקובץ הופך לקידוד windows-1255. אפשר לראות את זה לדוגמא אם פותחים את הקובץ ב- ++notepad, מצד ימין למטה:

ואז אם נמיר את הקובץ כולו ל- UTF8:

אז זה יעבוד!!

אוקיי, אז המרת הטקסט לבד זה לא הפתרון. מה עושים?

פתרון ראשון הוא להשתמש בקובץ הקונפיגורציה של Extent Report. יש כזה. יש קובץ קונפיגורציה שבו אפשר להגדיר נושאים שונים בנראות של הדו”ח. מצרפים אותו לפרויקט וטוענים אותו לדו”ח ככה:

String reportName = "My_Report_Path_And_Name"
configFilePath = "./extent-config.xml";
ReportManager report = new ReportManager(reportName, configFilePath);

בקובץ הזה ניתן להגדיר את ה- encoding ל- windows-1255:

<?xml version="1.0" encoding="UTF-8"?>
<extentreports>
  <configuration>
    <!-- report theme -->
    <!-- standard, dark -->
    <theme>dark</theme>

    <!-- document encoding -->
    <!-- defaults to UTF-8 -->
    <encoding>windows-1255</encoding>

    <!-- protocol for script and stylesheets -->
    <!-- defaults to https -->
    <protocol>https</protocol>

    <!-- title of the document -->
    <documentTitle>"Title of doc"
    </documentTitle>

    <!-- report name - displayed at top-nav -->
    <reportName>"Report name"</reportName>

    <!-- location of charts in the test view -->
    <!-- top, bottom -->
    <testViewChartLocation>bottom</testViewChartLocation>

    <!-- custom javascript -->
    <scripts>
    <script>
            <![CDATA[
 ]]>
    </styles>
  </configuration>
</extentreports>

ואז נפתרה לנו הבעיה – הדו”ח יוצג בעברית.

מה הבעיה עם הפתרון הזה? מחשבים שמשתמשים בקידוד שונה מ- windows-1255 כמו Linux או Mac, או אנשים שאין להם קידוד עברית על המחשב (נכנסים ממחשב בחו”ל לבדוק מיילים) לא יוכלו לראות את הדו”ח.

אז מה עושים?

הפתרון שאני ממליץ הוא בסיום כתיבת הדו”ח, מיד אחרי השורה:

// (3) - Generate the report
report.flush();

לבצע המרה של כל הקובץ ל- UTF8. זה אומר גם את הקובץ וגם את הטקסט בתוכו. מה שנרצה לעשות בעצם זה לפתוח קובץ חדש בקידוד UTF8 ולכתוב בו שורה שורה מהקובץ המקורי בקידוד UTF8. הנה פונקציה שאני כתבתי שזה מה שהיא עושה:

public static void convertFileEncoding(String sourcePath, Optional<String> targetPath, Optional<String> targetEncoding) throws IOException, InterruptedException{
    
    // Wait for file to exist - 10 seconds
    for (int i=0; i<20 ; i++) {
      if(!Files.exists(Paths.get(sourcePath)))
        Thread.sleep(500);
      else
        break;
    }
          
    File infile = new File(sourcePath);
    
    String trgtPath = targetPath.orElse(sourcePath + "Temp") ;
    String trgtEncoding = targetEncoding.orElse("UTF-8");
    File outfile = new File(trgtPath);
    
    // Convert		
    InputStreamReader fis = new InputStreamReader(new FileInputStream(infile));
    Reader in = new InputStreamReader(new FileInputStream(infile),fis.getEncoding());
    Writer out = new OutputStreamWriter(new FileOutputStream(outfile), trgtEncoding);

    int c;

    while ((c = in.read()) != -1){
      out.write(c);}

    in.close();
    out.close();
    fis.close();

    // if target path not specified - change the original file to target file
    if (!targetPath.isPresent()) {
      infile.delete();
      outfile.renameTo(new File(sourcePath));
    }
    
    
  }

הפונקציה הנ”ל מבצעת המרה של קובץ מקידוד אחד לקידוד אחר, כאשר קידוד ברירת המחדל שלה הוא UTF8

שורות 3-9 ממתינות שהדו”ח יסיים להכתב ויופיע ב- windows

שורות 11-15 פותחות את הקובץ המקורי לקריאה, ופותחות קובץ לכתיבה על פי הקידוד שאנחנו מעוניינים.

שורות 18-20 מבצעות בפועל את ההמרה שורה אחר שורה
לאחר מכן סוגרים את הקובץ.
בסוף, שורות  32-35 משנות שם לקובץ החדש או שומרות אותו בשם חדש.

 התוצאה:

זו השיטה העדיפה בעיני. UTF8 הוא קידוד מאוד פופולרי ובעצם קיים בכל מכשיר היום. שימוש בקידוד UTF8 יבטיח שכל מי שיפתח את הקוד בכל מחשב ובכל מקום יוכל לראות עברית באופן תקין.