Skip to content

chore: Upgrade to latest wdio - #2212

Merged
dprevost-LMI merged 4 commits into
webdriverio:mainfrom
dprevost-LMI:upgrade-latest-wdio
Sep 13, 2026
Merged

dprevost-LMI merged 4 commits into
webdriverio:mainfrom
dprevost-LMI:upgrade-latest-wdio

Conversation

@dprevost-LMI

Copy link
Copy Markdown
Contributor

No description provided.

```
[chrome 152.0.7977.64 linux #0-4] 1) Browser matchers should verify not localStorage item with options
[chrome 152.0.7977.64 linux #0-4] Cannot access 'expect' before initialization
[chrome 152.0.7977.64 linux #0-4] ReferenceError: Cannot access 'expect' before initialization
[chrome 152.0.7977.64 linux #0-4]     at Object.expect (/home/runner/work/expect-webdriverio/expect-webdriverio/lib/index.js:1:1)
[chrome 152.0.7977.64 linux #0-4]     at Object.get [as expect] (/home/runner/work/expect-webdriverio/expect-webdriverio/lib/index.js:2:648)
[chrome 152.0.7977.64 linux #0-4]     at Object.toHaveLocalStorageItem (/home/runner/work/expect-webdriverio/expect-webdriverio/lib/matchers/browser/toHaveLocalStorageItem.js:17:20)
[chrome 152.0.7977.64 linux #0-4]     at async Context.<anonymous> (/home/runner/work/expect-webdriverio/expect-webdriverio/playgrounds/mocha/test/specs/wdio-matchers.test.ts:33:13)
```
@dprevost-LMI

Copy link
Copy Markdown
Contributor Author

@greptileai, can you help me find the cause of this problem mentioned in webdriverio/webdriverio#15589 (comment) that is happening in this PR

@greptile-apps

greptile-apps Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

The regression is caused by an existing ESM module-graph problem in expect-webdriverio, rather than by toHaveText itself.

src/index.ts eagerly imports ./matchers.js before initializing/exporting getDefaultOptions. At least src/matchers/element/toHaveAttribute.ts and src/matchers/element/toHaveElementProperty.ts then import runtime values back from ../../index.js, creating a cycle:

index.ts -> matchers.ts -> matcher -> index.ts

When WebdriverIO 9.31.6 changes the worker’s dependency/evaluation path, this cycle is exposed through more than one ESM module instance. That accounts for both symptoms from #15589:

  • constants.ts is evaluated twice, producing separate DEFAULT_OPTIONS objects. The runner’s setDefaultOptions() can therefore update a different object from the one used by a matcher.
  • Re-entering index.ts before its exports are initialized triggers the temporal-dead-zone error, such as Cannot access 'getDefaultOptions' before initialization.

The PR’s change in src/matchers/browser/toHaveLocalStorageItem.ts from ../../index.js to the direct expect package import is the correct fix for that individual cycle. The remaining runtime imports from ../../index.js should be removed or moved behind a lower-level dependency/injection boundary as well. The deepmerge-ts upgrade in WebdriverIO 9.31.6 may have changed the resolution/evaluation path, but there is no evidence that it directly introduced a matcher or expect-webdriverio implementation change.

@greptile-apps

greptile-apps Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

The failure is an existing module-cycle/duplicate-instance problem in expect-webdriverio that the WDIO upgrade exposes; toHaveText is only where it becomes visible.

The direct cycle is:

src/index.ts
  -> ./matchers.js
  -> src/matchers/element/toHaveAttribute.ts
  -> ../../index.js

src/matchers/element/toHaveElementProperty.ts has the same runtime import. In src/index.ts, ./matchers.js is imported before expect and getDefaultOptions have been initialized. Re-entering index.js through those matchers therefore reads a TDZ binding and produces Cannot access 'getDefaultOptions' before initialization (or expect in the earlier failure).

The constants.ts double-load is the second symptom: the worker ends up evaluating two module instances, so each instance has its own DEFAULT_OPTIONS object. setDefaultOptions() updates one instance while toHaveText receives the default from the other. This explains why the feature flag appears in beforeEach but not inside the matcher.

The PR diff confirms that the relevant trigger is the WDIO 9.31.5 → 9.31.7 dependency update. WDIO 9.31.6 did not change expect-webdriverio code; its notable runner/config dependency change was deepmerge-ts 7 → 8. That can change the loader/evaluation order or dependency layout, exposing the latent cycle, but it is not the underlying singleton bug. @wdio/globals is not the cause: its expect export is a proxy to the runner global and does not initialize expect-webdriverio itself.

The change in this PR that replaces the ../../index.js import in src/matchers/browser/toHaveLocalStorageItem.ts with a direct expect package import fixes one instance of the cycle. The same correction is still needed in src/matchers/element/toHaveAttribute.ts and src/matchers/element/toHaveElementProperty.ts (or those matchers should use a lower-level dependency), and the playground should ensure only one physical expect-webdriverio package instance is resolved. Once those runtime back-imports are removed, both the TDZ error and the split DEFAULT_OPTIONS state should disappear.

@dprevost-LMI

Copy link
Copy Markdown
Contributor Author

@greptileai, what percentage are you confident this is the root cause? What makes you believe this is what is at play? What evidence do we have that deepmerge-ts could be involved?

@greptile-apps

greptile-apps Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

I’d put my confidence at roughly 85% that the underlying defect is the existing module-graph problem in expect-webdriverio, but only 25–35% that deepmerge-ts is specifically the trigger, and under 10% that deepmerge-ts itself is directly causing the TDZ or duplicate-module behavior.

The evidence for the module-graph diagnosis is:

  • The regression is reproducible at the WDIO 9.31.5 → 9.31.6 boundary.
  • The issue’s instrumentation shows constants.ts being evaluated twice in the same worker (id: 47 and id: 237). That directly supports two module instances/state objects, explaining why setDefaultOptions() and the matcher observe different DEFAULT_OPTIONS.
  • There are concrete runtime back-imports forming cycles. src/index.ts statically imports ./matchers.js before exporting expect/getDefaultOptions; src/matchers/element/toHaveAttribute.ts, src/matchers/element/toHaveElementProperty.ts, and src/softExpect.ts import runtime values back from ../../index.js. That is sufficient to make the observed Cannot access 'getDefaultOptions' before initialization error plausible.
  • The PR already fixes the same pattern in src/matchers/browser/toHaveLocalStorageItem.ts by importing expect directly from the expect package. That is useful corroborating evidence, although it does not prove this is the exact path exercised by toHaveText.

The evidence for deepmerge-ts is much weaker. The lockfile shows that WDIO 9.31.6 changed deepmerge-ts from 7.1.6 to 8.0.2, and @wdio/config/@wdio/utils depend on it. That establishes correlation and makes it a possible indirect trigger. However:

  • expect-webdriverio does not import deepmerge-ts.
  • deepmerge-ts merges configuration objects; it does not control Node’s ESM resolver or lexical-binding initialization.
  • There is no evidence in the issue, PR, or WDIO 9.31.6 diff that deepmerge-ts changes module resolution or loads expect-webdriverio.

So my earlier wording gave deepmerge-ts too much weight. The defensible conclusion is: the WDIO dependency update exposes a pre-existing cycle/duplicate-instance vulnerability; deepmerge-ts is one candidate indirect dependency change, not an established root cause.

The decisive checks would be to (1) pin only deepmerge-ts back to 7.x while keeping WDIO 9.31.6, and (2) remove all runtime back-imports from ../../index.js and verify whether the failure disappears without changing WDIO. Until those controlled comparisons or a module-resolution trace are available, I would not claim that deepmerge-ts is causal.

@dprevost-LMI
dprevost-LMI marked this pull request as ready for review September 13, 2026 20:59
@greptile-apps

greptile-apps Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge, with the upgraded dependency graph remaining consistent and the local-storage matcher retaining its documented behavior.

Summary

  • Aligns the primary WebdriverIO runner, framework, CLI, and browser packages on 9.31.9.
  • Refreshes Vitest snapshot and Jest linting dependencies.
  • Regenerates DOM and visual fixtures after the dependency update.
  • Preserves local-storage existence matching while avoiding the configured expectation module’s initialization path.

Reviews (1) · Last reviewed commit: "Upgrade to `9.31.9` with downgrade mocha..."

@dprevost-LMI
dprevost-LMI merged commit 7abab60 into webdriverio:main Sep 13, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant