All files / src/infra WaterClient.ts

0% Statements 0/52
0% Branches 0/1
0% Functions 0/5
0% Lines 0/51

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141                                                                                                                                                                                                                                                                                         
import path from "path";
import { Page } from "@playwright/test";
import { Browser, withBrowser } from "./Browser";
import { FetchSettingModel, MonthlyUsageModel } from "../domain/Water";
import { CommonEnv, Env } from "../Env";
import Logger from "bunyan";
 
export class WaterClient {
  readonly commonEnv: CommonEnv;
  readonly env: Env;
 
  constructor(commonEnv: CommonEnv, env: Env) {
    this.commonEnv = commonEnv;
    this.env = env;
  }
 
  async fetchMonthly(
    logger: Logger,
    setting: FetchSettingModel
  ): Promise<MonthlyUsageModel[]> {
    logger.info("fetch start");
    let usages: MonthlyUsageModel[] = [];
    try {
      await withBrowser(
        this.env.timeoutMs,
        async (browser: Browser): Promise<void> => {
          const page = await browser.newPage(logger);
          try {
            // ログインページに移動
            logger.info("goto login page");
            await page.goto(this.env.loginUrl);
            await page.locator("#fs-contents").waitFor();
            await page.screenshot({
              path: this.makeScreenshotPath("water-01-login-page.png"),
              fullPage: true,
            });
 
            // ログイン
            logger.info("input id and password");
            await page.locator("#loginId").fill(setting.userName);
            await page.locator("#password").fill(setting.password.value());
            await page.screenshot({
              path: this.makeScreenshotPath(
                "water-02-login-page-with-id-pw.png"
              ),
              fullPage: true,
            });
            logger.info("click login button");
            await page
              .locator("#thisform > div.area > div.areaR > button")
              .click();
            logger.info("wait for loading top page");
            await page.locator("#fs-contents").waitFor();
            await page.screenshot({
              path: this.makeScreenshotPath("water-03-top-page.png"),
              fullPage: true,
            });
 
            // 料金を取得
            const now = new Date();
            usages = usages.concat(
              await this.fetch(logger, setting, page, now)
            );
          } catch (err) {
            await page.screenshot({
              path: this.makeScreenshotPath("water-99-error.png"),
              fullPage: true,
            });
            throw err;
          }
        }
      );
    } finally {
      logger.info("fetch end");
    }
    return usages;
  }
 
  async fetch(
    logger: Logger,
    setting: FetchSettingModel,
    page: Page,
    now: Date
  ): Promise<MonthlyUsageModel[]> {
    logger.info("wait for loading usage data");
    const tables = await page.locator("#fs-contents .kenshin-day+.waterUsage");
    const tablesCount = await tables?.count();
 
    const usages: MonthlyUsageModel[] = [];
    for (let i = 0; i < tablesCount; i++) {
      // 日付取得
      const dateStrOrg = await tables.nth(i).locator("td").nth(0).innerText();
      const splited = dateStrOrg.split("/");
      const year = Number(splited[0]?.replace("R", "")) + 2018;
      const month = Number(splited[1]);
      const day = Number(splited[2]);
      const datetimeStr = `${year}-${splited[1]}-${splited[2]}T00:00:00.000Z`;
 
      // 使用量と料金を取得
      const amount = Number(
        (await tables.nth(i).locator("td").nth(2).innerText()).replace(",", "")
      );
      const yen = Number(
        (await tables.nth(i).locator("td").nth(5).innerText()).replace(",", "")
      );
 
      logger.debug(
        "%s(%d/%d/%d) %d[m^3] %d[yen]",
        dateStrOrg,
        year,
        month,
        day,
        amount,
        yen
      );
 
      const usage = usages.pop();
      Iif (usage) {
        usage.begin = datetimeStr;
        usages.push(usage);
      }
 
      usages.push({
        fetchSettingId: setting.id,
        year: year,
        month: month,
        begin: null,
        end: datetimeStr,
        amount: amount,
        yen: yen,
      });
    }
 
    return usages;
  }
 
  private makeScreenshotPath(fileName: string): string {
    return path.join(this.env.screenshotDir, fileName);
  }
}