playwrghtのサンプル | ツール・シミュレータ

ツール・シミュレータ

ツール・シミュレータ等のプログラミングをネタとしてブログ。

typecsriptでplaywightをやってみる。

 

 

{

  "name": "playwright01",

  "version": "1.0.0",

  "description": "",

  "main": "index.js",

  "scripts": {

    "test": "echo \"Error: no test specified\" && exit 1"

  },

  "keywords": [],

  "author": "",

  "license": "ISC",

  "dependencies": {

    "playwright-core": "^1.42.1"

  },

  "devDependencies": {

    "@types/node": "^20.11.30",

    "ts-node": "^10.9.2",

    "typescript": "^5.4.3"

  }

}

 

 

{

    "id":"normal",

    "cmds":[

        {"cmd":"wait","selector":"aaa"},

        {"cmd":"capture"},

        {"cmd":"fill","selector":"ccc"},

        {"cmd":"click","selector":"bbbb"}

    ]

}

 

 

 

{

    "headless": false,

    "channel": "chrome",

    "capture_dir": "C:\\mysoft\\node\\nodeap\\_samples\\playwright01\\capture",

    "screen_dir": "C:\\mysoft\\node\\nodeap\\_samples\\playwright01\\screen",

    "senario_file": "C:\\mysoft\\node\\nodeap\\_samples\\playwright01\\senario\\senario.json",

    "proxy_file": null,

    "screen_transition_wait":1000

}

 

 

{

    "name":"senario_name",

    "transitions":[

        {"sid":"000","goto":"http","nexts":[{"screen":"PAGE001","sid":"001"}]},

        {"sid":"001","file":"PAGE001.json","nexts":[{"screen":"PAGE002","sid":"002"},{"screen":"PAGE003","sid":"003"},{"sid":"aaaa"}]},

        {"sid":"002","file":"PAGE001.json","nexts":[{"screen":"PAGE002","sid":"002"},{"screen":"PAGE003","sid":"003"},{"sid":"aaaa"}]}

    ]

}

 

 

 

import { chromium, Page, Browser } from 'playwright-core';

import * as fs from 'fs';



 

// type/factory

 

type Config = {

  headless: boolean

  channel: string

  capture_dir: string

  screen_dir: string

  senario_file: string

  proxy_file: string | null

  screen_transition_wait: number

};

 

const checkConfig: (cfg: Config) => void = (cfg: Config) => {

  let { headless, channel, capture_dir, screen_dir, senario_file, proxy_file, screen_transition_wait } = cfg;

  if (!(tyb(headless) && tys(channel) && tys(capture_dir) && tys(screen_dir) && tys(senario_file) && (tys(proxy_file) || proxy_file === null) && tyn(screen_transition_wait))) {

    throw Error("Configファイルの型が不正です");

  }

  if (!directoryExists(capture_dir)) throw Error("capture_dirが不正です:" + capture_dir);

  if (!directoryExists(screen_dir)) throw Error("screen_dirが不正です:" + screen_dir);

  if (!fileExists(senario_file)) throw Error("senario_fileが不正です:" + senario_file);

  if (proxy_file !== null && !fileExists(proxy_file) && proxy_file !== null) throw Error("proxy_fileが不正です:" + proxy_file);

  if (screen_transition_wait < 0) throw Error("screen_transition_waitが不正です:" + screen_transition_wait);

}

 

const createConfig: (file: string) => Config = (file: string) => {

  const txt = fs.readFileSync(file, 'utf-8');

  const cfg = JSON.parse(txt) as Config;

  checkConfig(cfg);

  return cfg;

};

 

type Cmd = {

  cmd: string

  selector?: string

}

 

type Screen = {

  id: string

  cmds: Cmd[]

}

 

const createScreen: (file: string) => Screen = (file: string) => {

  const txt = fs.readFileSync(file, 'utf-8');

  return JSON.parse(txt) as Screen;

}

 

type Next = {

  screen?: string

  sid: string

}

 

type Transition = {

  sid: string

  goto: string

  file: string

  nexts: Next[]

}

 

type Senario = {

  name: string

  transitions: Transition[]

}

 

const doSenario: (senario: Senario, cfg: Config) => void = async (senario: Senario, cfg: Config) => {

  let capt = new Capture(cfg.capture_dir);

  let browser: Browser | null = null;

  try {

    browser = await chromium.launch({

      channel: cfg.channel,

      headless: cfg.headless,

    });

    const page = await browser.newPage();

    let transitionMap:{[key:string]:Transition} = {};

    for(const transition of senario.transitions) {

      transitionMap[transition.sid] = transition;

    }

    let nextTransition = senario.transitions[0];

  } catch (e) {

 

  } finally {

    if(browser !== null) await browser.close();

  }

}

 

const createSenario: (file: string) => Senario = (file: string) => {

  const txt = fs.readFileSync(file, 'utf-8');

  return JSON.parse(txt) as Senario;

}

 

// utillity

 

const t: (a: any) => string = (a: any) => {

  return typeof a;

}

 

const tys: (a: any) => boolean = (a: any) => {

  return t(a) === 'string';

}

 

const tyb: (a: any) => boolean = (a: any) => {

  return t(a) === 'boolean';

}

 

const tyn: (a: any) => boolean = (a: any) => {

  return t(a) === 'number';

}

 

const tya: (a: any) => boolean = (a: any) => {

  return Array.isArray(a);

}

 

const directoryExists: (path: string) => boolean = (path: string) => {

  if (!fs.existsSync(path)) return false;

  return fs.statSync(path).isDirectory();

}

 

const fileExists: (path: string) => boolean = (path: string) => {

  if (!fs.existsSync(path)) return false;

  return fs.statSync(path).isFile();

}

 

const getCurrentFormatedDate: () => string = () => {

  const date = new Date()

  const y = date.getFullYear();

  const m = ('0' + (date.getMonth() + 1)).slice(-2);

  const d = ('0' + date.getDate()).slice(-2);

  const h = ('0' + date.getHours()).slice(-2);

  const mi = ('0' + date.getMinutes()).slice(-2);

  const s = ('0' + date.getSeconds()).slice(-2);

  return y + m + d + h + mi + s;

}

 

class Capture {

  private count: number = 1;

  constructor(private readonly saveDir: string) {

    if (!directoryExists(saveDir)) {

      throw Error("ディレクトリが存在しません:" + saveDir);

    }

  }

 

  doCapture(page: Page, suffix: string) {

    let fileName = getCurrentFormatedDate() + "_" + suffix + "_" + this.count.toString() + ".png";

    page.screenshot({ path: '', fullPage: true })

  }

}

 

// main

const cfgPath = process.argv.length >= 3 ? process.argv[2] : ".\\config.json";

if (!fileExists(cfgPath)) {

  throw Error("ファイルが存在しません:" + cfgPath);

}

 

const cfg = createConfig(cfgPath);

console.log(cfg);

 

const senario = createSenario(cfg.senario_file);

console.log(senario);

 

doSenario(senario,cfg);