Skip to content

fix(storage): preserve IndexedDB Map and Set values - #42707

Merged
Yury Semikhatsky (yury-s) merged 4 commits into
microsoft:mainfrom
yury-s:fix-42703
Sep 14, 2026
Merged

Yury Semikhatsky (yury-s) merged 4 commits into
microsoft:mainfrom
yury-s:fix-42703

Conversation

@yury-s

Copy link
Copy Markdown
Member
  • Preserve Map and Set values, cycles, and shared references in IndexedDB snapshots, including Firefox cross-world wrappers.
  • Keep evaluate() serialization unchanged and add regression coverage.

Fixes #42703

Fixes: microsoft#42703

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

This comment has been minimized.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@yury-s
Yury Semikhatsky (yury-s) marked this pull request as ready for review September 14, 2026 16:28

function isMap(obj: any): obj is Map<unknown, unknown> {
try {
return obj instanceof Map || Object.prototype.toString.call(obj) === '[object Map]';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can be strict and drop [object Map]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instanceof Map fails for Firefox’s cross-world wrappers; removing the fallback breaks both IndexedDB roundtrip tests

Comment thread packages/injected/src/storageScript.ts Outdated

return { fallThrough: v };
});
}, { serializeMapAndSet: true });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expose this in evaluate?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do in a separate pr.

@github-actions

This comment has been minimized.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Comment on lines +316 to +317
const iterator = value.entries();
const next = new Map().entries().next;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the idea here that we're trying to use our Map instead of whatever is in the object's realm? or are we just trying to avoid our code being observable by the page?

regardless, i think this maybe should be const iterator = Map.prototype.entries.call(value) to avoid it having overridden value.entries = function() { ... })

@yury-s Yury Semikhatsky (yury-s) Sep 14, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This to workaround Firefox not exposing iterator.next cross worlds. For storage state this code is running in the utility world, so we don't need to worry about entries override. I'll probably update it in the pr where this option become public on evaluate.

const s: SerializedValue[] = [];
const id = ++visitorInfo.lastId;
visitorInfo.visited.set(value, id);
const iterator = value.values();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto with Set.prototype.values.call(value)

@yury-s
Yury Semikhatsky (yury-s) merged commit d4ce80d into microsoft:main Sep 14, 2026
41 of 43 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Test results for "tests 1"

2 failed
❌ [firefox-library] › library/browsercontext-storage-state.spec.ts:453 › should work when service worker is intefering and the origin is not open @firefox-ubuntu-22.04-node20
❌ [playwright-test] › reporter.spec.ts:251 › created › should not have internal error when steps are finished after timeout @windows-latest-node22

7 flaky ⚠️ [chromium-library] › library/browsercontext-page-event.spec.ts:160 › should work with Shift-clicking `@chromium-ubuntu-22.04-arm-node20`
⚠️ [chromium-library] › library/chromium/chromium.spec.ts:213 › should intercept service worker requests (main and within) `@realtime-time-library-chromium-linux`
⚠️ [chromium-library] › library/video.spec.ts:699 › screencast › should capture full viewport on hidpi `@chromium-ubuntu-22.04-node24`
⚠️ [firefox-library] › library/browsercontext-cookies-third-party.spec.ts:257 › third party 'Partitioned;' cookies `@firefox-ubuntu-22.04-node20`
⚠️ [firefox-library] › library/browsercontext-cookies-third-party.spec.ts:470 › top level 'Partitioned;' cookie and same origin iframe `@firefox-ubuntu-22.04-node20`
⚠️ [firefox-page] › page/page-event-request.spec.ts:181 › should return response body when Cross-Origin-Opener-Policy is set `@firefox-ubuntu-22.04-node20`
⚠️ [playwright-test] › ui-mode-trace.spec.ts:189 › should show snapshots for steps `@windows-latest-node22`

51719 passed, 1247 skipped


Merge workflow run.

@github-actions

Copy link
Copy Markdown
Contributor

Test results for "MCP"

8564 passed, 1446 skipped


Merge workflow run.

@github-actions

Copy link
Copy Markdown
Contributor

Hi, I'm the Playwright bot and I triaged the CI failures on this PR.

🟢 Both failures are pre-existing — neither is caused by this PR. The Firefox storage-state failure is broken on main right now (fails 100% of Firefox runs, including push runs on 654654fc, da3553d3, 52a0e720), and the Windows reporter timeout is a known Windows-only flake that has timed out on main before.

Details

This PR only touches IndexedDB snapshot serialization: serializeAsCallArgument gains an opt-in extendedSerialization flag, and only storageScript.ts passes it. The evaluate() path is byte-for-byte unchanged, so nothing outside storage-state IndexedDB collection is reachable from the diff. The PR's own new tests all pass.

Pre-existing flake / infra

  • [firefox-library] › library/browsercontext-storage-state.spec.ts:453 › should work when service worker is intefering and the origin is not open — broken on Firefox independently of this PR. In the aggregated CI results this test is 0 passed / 8 failed on firefox-library while chromium-library (9/9) and webkit-library (8/8) are green. The failures include push runs on main at 654654fc, da3553d3 and 52a0e720, across firefox-ubuntu-22.04-node20, firefox-macos-15-large/xlarge, firefox-windows-latest and tracing-firefox. Same assertion everywhere — the service-worker-written fromServiceWorker localStorage entry leaks into the snapshot:

    Error: expect(received).toEqual(expected) // deep equality
    + Object { "name": "fromServiceWorker", ... }
    

    It has failed on Firefox since it landed in fix(chromium): bypass service workers on the storage state page #42664 (fix-42656), so this looks like the Firefox side of [Bug]: browserContext.storageState() runs third-party page JS and can fail when a visited origin has a service worker #42656 not being covered by that fix — worth a separate look, but not this PR's doing.

  • [playwright-test] › reporter.spec.ts:251 › created › should not have internal error when steps are finished after timeout — Windows-only timeout flake. The same test (merged variant of the same parametrized block, same file) has timed out at ~31s on windows-latest-node22 on push runs on main (04fb72b4, 77e4a17d) and on unrelated PRs docs(locator): drop type markup from ariaSnapshotJSON details #42136 and test: race between disabling interception and network request in chromium #42254. The test is simply close to the limit on that bot: mean 8.0s but p95 11.5s and max 36.1s on windows-latest-node22, versus a 7.9s max on every Linux/macOS bot, against a 30s timeout. It also timed out and was rescued on retry on an earlier commit of this PR (5cf3e2a6), and passed on all other bots.

Method: queried the aggregated CI results DB (2021 runs, topped up with update --lookback-days 3), grouping on (project_name, file, test_title).

Triaged by the Playwright bot - agent run

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.

[Bug]: storageState({ indexedDB: true }) silently empties Map and Set values

3 participants