サンダルで靴屋に行ったけど試着時に靴下を貸してくれた

起こったこと

妻がサンダルを履いて買い物に出かけた。その際に靴を買うことになったが、靴下を履いていない。直で試着するのは憚れるところであった。

靴下を借りれた

「靴下がないので試着はちょっと遠慮したいです」と言ったところ「でしたら、靴下お貸ししますか?」と答えてもらえた。靴下を借りて試着を成功することができた。

htmlでホバー時に文字サイズを大きくする際、下の要素がずれるのをやめたかった

起こったこと

ホバー時に文字を大きくする処理を以下のようにCSSで書いた。

<style>
    .hogehoge {}

    .hogehoge:hover {
      font-size: 130%;
    }
</style>
<div class="hogehoge">
  文字を大きく
</div>
<p>
  ここはそのまま
</p>

しかし、対象となる要素が増加した文字サイズ分広がっていて、下にある要素も文字サイズが増えた分下がる。かくかくしていて見栄えが良くなかった。

対処した方法

transform: scale()を使うことにした。transform-originの設定も色々と変えると大きくなる起点も変えられる。うまくいかないときはこれも変えてみること。

developer.mozilla.org

<style>
    .piyopiyo {}

    .piyopiyo:hover {
      transform: scale(1.3);
      transform-origin: left;
    }
</style>
<div class="piyopiyo">
  文字を大きく
</div>
<p>
  ここはそのまま
</p>

PlayWright+MonoRepoはどうするのがよいのだろう

monorepoとE2E

コンポーネントを共有するようなWebアプリケーションmonorepoがあるとして、これらはどのようにするのが良いのか悩んでいる(現在進行形)

こういうのにしてみたけど

monorepo/
├── common # コンポーネントなど、projectsが呼び出す共通のデータが格納されているディレクトリ
├── e2e # テストが入ったディレクトリ
└── projects # プロジェクトのモノレポ
    ├── hogehoge # hogehogeプロジェクト
    └── piypiyo # piyopiyoプロジェクト

hogehogeとpiyopiyoは似通ったシステムであり共通しているデータもあるが、それぞれ独自の機能も存在している。E2Eテストを書く場合はプロジェクトごとに書く必要がある。なお、すべてnode.js、またはtypescriptで記述されている。

e2eディレクトリには共通するテストを書き、それらは関数にて呼び出すようにする。

// e2e/toppage.test.ts
import { test, expect, Page } from "@playwright/test";
export const toppageTest = (specData: any) => {
  test("トップページテスト1", async ({ page }) => {
    await page.goto("/");
    // ...
  } );
}

projectはこれをimportして実行する。また、projectごとに行いたいテストはe2eディレクトリのnode_modules内のplaywrightをimportし、テストケースを記述する。

// projects/hogehoge/e2e/toppage.test.ts
import { toppageTest } from "../../../e2e/toppage.test;
import { test, expect, Page } from "../../../e2e/node_modules/@playwright/test";

const specData = {}; // hogehogeっぽいデータ

toppageTest(specData); // 共通のテスト

test("hogehogeプロジェクトのトップページ特有のテスト", async ({ page }) => {
  // hogehogeプロジェクトのトップページ特有のテスト
});

これらはtypescriptで記述してあるので、tsconfig.jsonのpathsで設定を変えてあげた。

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@e2e": ["../../../e2e/*"],
    },
  }
}

とりあえずこういう形になった。

// projects/hogehoge/e2e/toppage.test.ts
import { toppageTest } from "@e2e/toppage.test;
import { test, expect, Page } from "@e2e/node_modules/@playwright/test";

const specData = {}; // hogehogeっぽいデータ

toppageTest(specData); // 共通のテスト

test("hogehogeプロジェクトのトップページ特有のテスト", async ({ page }) => {
  // hogehogeプロジェクトのトップページ特有のテスト
});

なんかやりかたに進展があったらまた書いてみます。

Playwrightで非同期でボタンを複数押そうとしたら安定しなかった

version情報

"@playwright/test": "1.22.2"

起こったこと

Webアプリケーション内にあるボタンを二つ押すと遷移できるページで、非同期で二つのボタンを押そうとしたけど出来なかった。

前提

例えば、ボタン1とボタン2を押すと下の要素に「二つのフラグが立ちました」と表示されるWebアプリケーションがあるとする。

(ごちゃごちゃして申し訳ない)

コードではこう書いた

test("ボタンを非同期で二つ押す", async ({ page }) => {
  await page.goto("/");
  const btn1 = page.locator(`text="ボタン1"`);
  const btn2 = page.locator(`text="ボタン2"`);
  const btns = [btn1, btn2];
  await Promise.all(btns.map(async (b) => await b.click()));
  await expect(page.locator(".flager")).toHaveText(/二つのフラグが立ちました/);
});

数回このコードで実行してみたが、Chromiumeだけ成功するパターン、firefoxだけ成功するパターンなど、いろいろと不思議なことが起きた。

こうした

test("ボタンを順繰りで二つ押す", async ({ page }) => {
  await page.goto("/");
  const btn1 = page.locator(`text="ボタン1"`);
  const btn2 = page.locator(`text="ボタン2"`);
  const btns = [btn1, btn2];
  for (let btn of btns) {
    await btn.click();
  }
  await expect(page.locator(".flager")).toHaveText(/二つのフラグが立ちました/);
});

こう書いたら安定した。

アプリ側の実装はこのような感じ

let flag1 = false;
let flag2 = false;
const btn1 = document.getElementById("button1");
const btn2 = document.getElementById("button2");

const flag1AndFlag2 = () => {
  if (flag1 && flag2) {
    const p = document.querySelector(".flager") as HTMLParagraphElement;
    p.innerText = "二つのフラグが立ちました";
  }
};

btn1?.addEventListener("click", () => {
  flag1 = true;
  flag1AndFlag2();
});
btn2?.addEventListener("click", () => {
  flag2 = true;
  flag1AndFlag2();
});

jszipで圧縮してもサイズ変わらない感じあった

version情報

    "typescript": "^4.7.4"
    "jszip": "^3.10.1"

起こったこと

jszipを使ってzipデータを作成しようとしたらあんまり圧縮されてる感じがなかった。 stuk.github.io

import fs from "fs";
import jszip from "jszip";
import { text } from "./text"; // 60,000文字ぐらいのテキスト

const zip = new jszip();
zip.file("test.txt", text);

zip.generateAsync({ type: "nodebuffer" }).then((blob) => {
  fs.writeFileSync("test.zip", blob);
});

zipデータ

というかオプション当てないとどうも無圧縮っぽい。

オプション当てた

{ compression: "DEFLATE"}というオプションを当てた

stuk.github.io

defaultがSTORE (no compression)って書いてあった

zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" }).then((blob) => {
  fs.writeFileSync("test.zip", blob);
});

およそ七割が圧縮された

Amplifyのビルドに使ったArtifactをCLIからDownloadしたい

起こったこと

AWS Amplifyに使った過去のビルド用データが必要になった。Amplifyコンソールからダウンロードは可能。

ただCLIの「list-artifacts」には該当のArtifactは見つからない。その他、SDKからListArtifactを叩いても出てこなかった。 https://docs.aws.amazon.com/cli/latest/reference/amplify/list-artifacts.html

$ aws amplify list-artifacts --app-id ****** --branch-name ***** --job-id NUMBER
{
    "artifacts": []
}

GetListじゃなくてGetJobだった

GetJobの方のsteps以下にあるartifactsUrl内のURLがそのビルド用データだった。 https://docs.aws.amazon.com/cli/latest/reference/amplify/get-job.html

$ aws amplify get-job --app-id ****** --branch-name ***** --job-id NUMBER
{
    "job": {
...
        "steps": [
            {
                "stepName": "",
...
                "artifactsUrl": "ここのURL",

aws s3にアップロードされているデータの検索

起こったこと

AWS S3に挙げられている古いJSONデータを探す必要が出た。

awsのs3コマンドかs3cmdコマンドか

s3cmdだと深い層(再帰的)の表示が出来そうになかったのでawsコマンドを使った。軽く調べてみたレベルなのでもしかしたらきちんと調べたらs3cmdでいけるかもしれない。

こんなコマンド

$ aws s3 ls s3://****/ --recursive | sort -nr | grep hogehoge.json

ワイルドカードは使えないらしいのでパイプであれこれ渡して表示を絞った。

参考

https://stackoverflow.com/questions/32840053/amazon-s3cmd-ls https://stackoverflow.com/questions/39857802/check-if-file-exists-in-s3-using-ls-and-wildcard https://blog.hello-world.jp.net/posts/aws-4254