#!/bin/sh # script/test-e2e: build the extension and drive the real popup in a real # Chromium inside a pinned container. Our own extension to # scripts-to-rule-them-all. # # Deliberately NOT called by script/check or script/test: REPO_POLICIES.md # caps make test at 60 seconds and a browser suite does not fit. Run it # yourself before touching popup views. ESLint's no-undef now catches a # used-but-not-imported identifier in make check, but only this suite sees # what a view actually does when it runs. # .gitea/workflows/e2e.yml also runs it on every push, in a job separate # from check so that cap and the local fast path both stay intact. # # Docker is the only prerequisite. The repo reaches the container as a # build context and the extension is built inside it (see # tests/e2e/Dockerfile), so nothing here depends on the node, yarn or make # on the machine that starts the run. That is not a convenience: a bind # mount cannot work under Gitea Actions, and the runner image's node is too # old to install this repo's dependencies. set -eu SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)" ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)" # Each run builds, runs and then removes an image under a tag of its own. # Under one tag shared by every run, a second clone's build moves the tag # off this run's image, and the image store can then delete that untagged # image before or while this run uses it. The tag is random rather than # $$ because CI jobs share one docker daemon, but each job's container # numbers its processes from scratch. IMAGE="$("$SCRIPT_DIR/projectname")-e2e-chrome:$(od -An -N6 -tx1 /dev/urandom | tr -d ' \n')" cleanup() { # No image to remove when the build failed or was interrupted. if docker image inspect "$IMAGE" >/dev/null 2>&1; then docker image rm "$IMAGE" >/dev/null fi } main() { cd "$ROOT" if ! command -v docker >/dev/null 2>&1; then echo "test-e2e: docker is required to run the e2e suite" >&2 exit 1 fi trap cleanup EXIT trap 'cleanup; exit 130' INT TERM echo "Building the Chrome e2e image (extension included)..." # --no-cache: the image build runs make build and its checks, and a # cached layer is a check that did not run. docker build --no-cache -t "$IMAGE" -f tests/e2e/Dockerfile . echo "Running e2e suite in the pinned Playwright container..." # --ipc=host: Chromium's shared-memory needs more than the default # 64MB /dev/shm or renderers crash. # HOME=/tmp: the image's root home is not a reliable place for the # browser profile. # PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS=1: without it, # ctx.route() intercepts page requests only, and every fetch made by # the MV3 background service worker — the JSON-RPC calls behind # every approval the suite drives among them — goes to the real # internet. The flag is experimental and Playwright may drop or # rename it. It cannot break silently: the harness asks the worker # for one request of its own at launch and aborts the whole suite # if it does not reach the route handler (see the interception # canary in tests/e2e/harness.js). If a future Playwright removes # the flag, that probe is what will fail, and the fix is either a # replacement mechanism or an honest downgrade of the isolation # claim in tests/e2e/network.js and README.md — not deleting the # probe. The image is pinned by digest, so this can only ever bite # on a deliberate bump. docker run --rm \ --ipc=host \ -e HOME=/tmp \ -e PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS=1 \ -e "E2E_TRACE_NETWORK=${E2E_TRACE_NETWORK:-0}" \ "$IMAGE" \ node tests/e2e/run.js # Where chrome.storage.local lives, and what moves it: two unpacked loads # from two different paths in one profile, with the shipped manifest and # again with `key` stripped out. Its own browser sessions — four of them — # because the whole subject is what happens ACROSS loads, which the suite # above cannot express with one. # # No PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS here: this drives no # RPC and installs no route handlers, and the browser is started with # --host-resolver-rules=MAP * ~NOTFOUND so nothing it does can leave. echo "Running the extension-id and storage-partition observations..." docker run --rm \ --ipc=host \ -e HOME=/tmp \ "$IMAGE" \ node tests/e2e/storagePartition.js } main "$@"