test: adapt E2E suite to v4 and fix regressions it caught - #4012
Open
B4nan wants to merge 15 commits into
Open
Conversation
- `LinkeDOMCrawler`'s `enqueueLinks` helper referenced the non-existent global `document` instead of the parsed window, crashing every call at runtime - `ErrorSnapshotter.saveHTMLSnapshot()` returned the record key with a v3-style `.html` suffix, so the subsequent `getPublicUrl()` lookup missed and `firstErrorHtmlUrl` never made it into the crawler statistics - `JSDOMCrawlingContext`/`LinkeDOMCrawlingContext` did not override `enqueueLinks`, exposing the strict urls-required signature even though the runtime helper extracts URLs from the parsed document - `LinkeDOMCrawler` constructor now accepts no arguments, like the other crawlers
- bump the pinned `apify` SDK to 4.0.0-beta.22 (beta.19 imports `snakeCaseToCamelCase` from `@crawlee/utils`, which no longer exists) - adapt `tools.mjs` to the fs-storage on-disk layout (`__default__` aliases, extensionless key-value records) and the `@crawlee/utils` exports split - migrate test actors to the v4 APIs: `logger` option + `ApifyLogAdapter` instead of `log`, hooks receiving `gotoOptions` via the crawling context, `session.setCookie()`, custom `SessionPool` instead of `sessionPoolOptions`, WHATWG `Response` from `sendRequest`, `registerDeferredCleanup` for dataset writes that must survive a throwing handler, and explicit enqueue strategies now that `include` globs are ANDed with the default same-hostname strategy - configure TLS verification on the http client in the ignore-ssl test (the crawler-level `ignoreSslErrors` option is not wired to the default client) - pin session fingerprints in the impit test (the random default fingerprint overrides the client's browser impersonation) - add ES2022 to actor tsconfig `lib` (bare `["DOM"]` dropped the ES lib and broke compilation on `ErrorOptions`) - skip the zero-concurrency queue test (relies on the removed v3 client-side `inProgress` set) and fix the camoufox fetch retry loop re-fetching 5x - comment out the LOCAL storage matrix entry (@apify/storage-local does not support v4 yet) and drop a duplicate `apify` dependency key that silently downgraded the curl-impersonate actor to SDK v3
- rewrite the curl-impersonate actor's custom http client against the v4 `BaseHttpClient` from `@crawlee/http-client` (implement `fetch()` returning a WHATWG `Response`; the base class now handles redirects/cookies/proxies), fix its tsconfig (`module` must be NodeNext to match the inherited `moduleResolution`), and drop stale uuid assertions the actor stopped pushing - replace `browser.process()` (a Puppeteer-only API that does not exist on Playwright's `Browser`) with object-identity browser numbering in the stagehand-concurrent actor - regenerate the jsdom/linkedom public API reports for the `enqueueLinks` context override
The LOCAL storage backend is disabled for v4 (no v4-compatible @apify/storage-local yet), but every actor still depended on it, and its better-sqlite3 native build fails on the platform image (musl, Node 24, no prebuilt binary, no Python) - which broke `apify push` for the whole PLATFORM matrix.
- drop `--no-optional` from actor Dockerfiles: v4's fs-storage depends on the `@crawlee/fs-storage-native` napi package whose per-platform binaries are optionalDependencies, so every platform actor crashed on startup with a missing `linux-x64-musl` binary - add `@crawlee/types` to root devDependencies - workspace packages only get a root node_modules link when declared, so `tsc` in the e2e actors could not resolve it on a clean frozen install (local installs masked this) - filter invalid header names (the parsed status line) out of curl-impersonate responses before constructing the fetch Response - log the platform run status in the e2e harness when it is not SUCCEEDED
The napi loader of @crawlee/fs-storage-native throws at import time on platforms without a published binary (e.g. linux musl, which the Apify platform images use), and @crawlee/core imports @crawlee/fs-storage eagerly through its service locator - so merely importing crawlee crashed there. Require the native module on first storage use instead.
- wipe the base image's preinstalled node_modules before npm install in every actor Dockerfile (both stages of multistage builds) - the apify/actor-node image ships an SDK v3 install that survived our install and broke the -ts builds' type-checking against the copied v4 packages - pin `apify` to 4.0.0-beta.22 in the actors instead of the floating next-v4 dist-tag, so platform runs test the same SDK build as the local suite
Passing any scoped service to a crawler (e.g. just `logger`) created a fresh ServiceLocator whose unset slots later materialized defaults - so a crawler with a custom logger silently detached from a globally configured storage backend (such as the platform storage set by the Apify SDK) and fell back to the file-system one. The scoped locator now inherits the ambient locator's already-set services for anything not explicitly provided.
- wipe the preinstalled node_modules of the browser base images before the `COPY --from=builder` in browser actor Dockerfiles - buildkit cannot copy the builder's file:-dep symlinks over the existing directories - add skipLibCheck to the remaining -ts actor tsconfigs; the platform build otherwise type-checks dependency d.ts files (quick-lru) and core's d.ts reference to the type-only @standard-schema/spec, which is not installed in the actor's isolated node_modules
The Cloudflare challenge page is a 403, and `throwOnBlockedRequest` runs after the post-navigation hooks - so the hook must return the reloaded response via `handleCloudflareChallengeHook()`, otherwise the crawler throws on the original challenge response before ever solving it.
The internal `userData.__crawlee` bag (carrying e.g. `skipNavigation`) is non-enumerable on userData objects owned by a Request instance, so the constructor's spread silently dropped it when a request was re-wrapped from another instance's data - which happens on the platform request queue's local-cache read path and lost `skipNavigation` there. Read the bag explicitly before spreading.
Documents the v4 changes the e2e suite tripped over that were missing from the guide: the `log` -> `logger` crawler option (with `ApifyLogAdapter` and the missing `setLevel`), `include` patterns being ANDed with the enqueue strategy instead of replacing it, the `@crawlee/utils` public//internal entry point split, the removed `storageObject` property, and the switch of the default HTTP client to impit with session-fingerprint-driven impersonation.
- unit tests for the three package regressions fixed in this PR: `__crawlee` bag preservation on request re-wrap, ambient service inheritance in crawler-scoped service locators, and the error snapshotter record key - promote `getServicesIfSet()` to the (non-exported) service locator interface, dropping the double cast at the call site - guard the manual Cloudflare hook snippet in the upgrading guide against clobbering the response on no-challenge pages - drop a dead `?? 'GET'` fallback and fix a copied Dockerfile comment in the curl-impersonate actor
…moufox test The target hard-blocks datacenter IP ranges outright (block page instead of a solvable challenge), and the verbose flag keeps the challenge detection visible in the nightly logs for triage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Gets the E2E test suite running against v4. The suite hadn't been run since the v4 rewrite and everything failed on startup. After these changes the MEMORY run passes locally end to end, and getting there surfaced a few real regressions in the packages themselves.
Package fixes
LinkeDOMCrawler'senqueueLinkshelper referenced the globaldocument(which doesn't exist in Node) instead of the parsed window, so every call crashed at runtime.ErrorSnapshotter.saveHTMLSnapshot()returned the record key with a v3-style.htmlsuffix, so the follow-upgetPublicUrl()lookup missed andfirstErrorHtmlUrlnever made it into the crawler statistics.JSDOMCrawlingContext/LinkeDOMCrawlingContextdidn't overrideenqueueLinks, exposing the strict urls-required signature even though the runtime helper extracts URLs from the parsed document.LinkeDOMCrawlercan now be constructed without arguments, like the other crawlers.E2E suite changes
apifySDK to 4.0.0-beta.22 (beta.19 importssnakeCaseToCamelCasefrom@crawlee/utils, which no longer exists there).tools.mjsto the fs-storage on-disk layout (__default__aliases, extensionless key-value records) and to the@crawlee/utilsexports split.loggeroption withApifyLogAdapterinstead oflog, hooks readinggotoOptionsfrom the crawling context,session.setCookie(), a customSessionPoolinstead ofsessionPoolOptions, the WHATWGResponsereturned bysendRequest,registerDeferredCleanupfor dataset writes that must survive a throwing handler, and explicit enqueue strategies now thatincludeglobs are ANDed with the default same-hostname strategy.ignoreSslErrorsoption is not wired to the default client in v4. That dangling option deserves a separate fix or removal, since it currently does nothing.lib(a bare["DOM"]drops the ES lib and broke compilation onErrorOptions).inProgressset, which the rewritten queue doesn't have.apifydependency key that silently downgraded the curl-impersonate actor to SDK v3.@apify/storage-localdoesn't support v4.