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

JSのモーダル(prompt)に入力したい

Version情報

"typescript": "^4.7.4"
"@playwright/test": "^1.22.2"

起こったこと

特定のものを削除する際によく出る「deleteと入力してください」のあれをE2Eテストしようとしたらなんかうまくいかなかった。

こんな感じ

  <main>
    <div>
      <p id="test-text">この文字が邪魔なので消したい</p>
      <button id="delete">削除</button>
    </div>
  </main>
const deleteButton = document.getElementById("delete");

deleteButton?.addEventListener("click", async () => {
  const result = prompt("削除したければdeleteと入力してください", "");
  if (result && /delete/.test(result)) {
    deleteSome();
    alert("成功");
  } else {
    alert("失敗");
  }
});

const deleteSome = () => {
  const test = document.getElementById("test-text") as HTMLParagraphElement;
  test.innerText = "-";
};

テストコードはこんな感じ

test("delete test", async ({ page }) => {
  await page.goto("/");
  await page.click('text="削除"');
  await expect(page.locator("#test-text")).toHaveText("-");
});

公式にあった

playwright.dev

こんな感じにした

test("delete test", async ({ page }) => {
  await page.goto("/");
  page.on("dialog", async (dialog) => {
    await dialog.accept("delete");
  });
  await page.click('text="削除"');
  await expect(page.locator("#test-text")).toHaveText("-");
});

page.on("dialog", callback)がpage.click()より手前に記述されているところに注目。

インスペクションしたかった

Version情報

"typescript": "^4.7.4"
"@playwright/test": "^1.22.2"

起こったこと

PlayWrightを本番環境で実行するとGoogleAnaryticsで拾っちゃってこまったので、ブラウザ実行時にインスペクションし特定のURLへ送信するときにAbortした

書いたもの

pageメソッドrouteを使う。

playwright.dev

以下のような処理を書いた。

test.beforeEach(async ({ page }) => {
  await page.route(/google-analytics\.com/, async (route) => {
    await route.abort("aborted");
  });
});

fixtures.override的な書き方だとこんな感じ

import { test, expect, Page } from "@playwright/test";

const test = base.extend<{ page: Page }>({
  page: async ({ page }, use) => {
    await page.route(/google-analytics\.com/, async (route) => {
      await route.abort("aborted");
    });
    await use(page);
  },
});

test("hogehoge test", async ({ page }) => {
  await page.goto("/");
  ....
});

package.jsonで--omit=devしてもdevDependenciesのモジュールが実行できるのはグローバルのそれを実行しているからかもしれない

バージョン情報

$ node -v
v16.15.1
$ npm -v
8.11.0

起こったこと

本番環境ではパッケージの量をなるべく少なくしたいので、本番環境作成時に必要としないdevDependenciesのモジュールをインストールしないようにしたかったのだが、いくらnpm i --omit=devしてもdevDependenciesでインストールしたモジュールが動いた。

npm scriptはglobalインストールされたパッケージも実行しているみたい

npm i -g ***でインストールされたモジュールを実行できるみたい。

なので動いていてもよかったみたいだ。

でも、ローカルとグローバルどっちが優先されるんだろうか。いつか調べよう

ちなみに--omit=devでdevDependenciesのディレクトリの中身はなかった

node_modules以下にdevDependenciesのモジュールのディレクトリは存在するが中身が空だった。ちなみにnode_modulesを削除して、再度--omit=devでインストールしても同じだった。空ディレクトリだけ作られるのナゾ。

動的なページをpage.$でDOMを取ろうとするとうまくいったりいかなかったりした

version情報

Ubuntu: 20.04
"@playwright/test": "1.22.2"
node: v16.15.1

起こったこと

動的なHTML要素をpage.$(QUERY)でとろうとしたら、Chromiumだけエラーになったりした。

<!--HTML-->
<div id="add">
</div>
const add = document.querySelector("#add") as HTMLDivElement;
setTimeout(() => {
  add.innerHTML = `<div><span data-name="momo">ももたろう</span><span data-name="kin">きんたろう</span></div>`;
}, 100);
import { test, expect } from "@playwright/test";

test("should show $ case1", async ({ page }) => {
  await page.goto("/");
  const momotarou = await page.$(`[data-name="momo"]`);
  expect(await momotarou?.innerText()).toBe("ももたろう");
  const kintarou = await page.$(`[data-name="kin"]`);
  expect(await kintarou?.innerText()).toBe("きんたろう");
});
Error: expect(received).toBe(expected) // Object.is equality

Expected: "ももたろう"
Received: undefined

  4 |   await page.goto("/");
  5 |   const momotarou = await page.$(`[data-name="momo"]`);
> 6 |   expect(await momotarou?.innerText()).toBe("ももたろう");
    |                                        ^
  7 |   const kintarou = await page.$(`[data-name="kin"]`);
  8 |   expect(await kintarou?.innerText()).toBe("きんたろう");
  9 | });

    at /home/kuzunoha/project/playwright_test/tests/index.spec.ts:6:40

$だと動的な要素を取るの大変みたい

よくわからんけどpage.$だと動的なのを取るのがうまくいかないケースがありそう。

chromiumだけエラーになるパターンや、firefox,webkitもダメなパターンがあった。

page.locatorを使ったら安定した

page.locatorを使ったら安定した。

test("should show $ case2", async ({ page }) => {
  await page.goto("/");
  const momotarou = page.locator(`[data-name="momo"]`);
  expect(await momotarou?.innerText()).toBe("ももたろう");
  const kintarou = page.locator(`[data-name="kin"]`);
  expect(await kintarou?.innerText()).toBe("きんたろう");
});

page.locator(`text="foobar"`)だと取れなかったところ

version情報

"@playwright/test": "1.22.2"

起こったこと

こういったインライン要素が入った文字を完全一致で取得できなかった。

<p id="foobar">foo<strong>bar</strong></p>
await page.click(`text="foobar"`)
/**
 *Timeout of 30000ms exceeded.

  page.click: Target closed
  =========================== logs ===========================
  waiting for selector "text="foobar""
  ============================================================
  */

ここに書いてあった

playwright.dev

text="Log in" - text body can be escaped with single or double quotes to search for a text node with exact content. For example, does not match because contains a single text node that is not equal to . However, matches , because contains a text node . This exact mode implies case-sensitive matching, so will not match .text="Log"

でも、完全一致が使いたい

正規表現が使えるのでこれをやったら動いた。

await page.click(`text=/^foobar$/`)