diff --git a/packages/playwright-core/src/server/frames.ts b/packages/playwright-core/src/server/frames.ts index 787fae44fe..fb4dcee705 100644 --- a/packages/playwright-core/src/server/frames.ts +++ b/packages/playwright-core/src/server/frames.ts @@ -1692,6 +1692,17 @@ export class Frame extends SdkObject { if (db.name) indexedDB.deleteDatabase(db.name!); } + + // Clean StorageManager + const root = await navigator.storage.getDirectory(); + const entries = await (root as any).entries(); + // Manual loop instead of for await because in Firefox's utility context instanceof AsyncIterable is not working. + let entry = await entries.next(); + while (!entry.done) { + const [name] = entry.value; + await root.removeEntry(name, { recursive: true }); + entry = await entries.next(); + } }, { ls: newStorage?.localStorage }).catch(() => {}); } diff --git a/tests/library/browsercontext-reuse.spec.ts b/tests/library/browsercontext-reuse.spec.ts index c25d66d588..057bc1d223 100644 --- a/tests/library/browsercontext-reuse.spec.ts +++ b/tests/library/browsercontext-reuse.spec.ts @@ -15,13 +15,16 @@ */ import { browserTest, expect } from '../config/browserTest'; -import type { BrowserContext } from '@playwright/test'; +import type { BrowserContext, BrowserContextOptions } from '@playwright/test'; -const test = browserTest.extend<{ reusedContext: () => Promise }>({ +const test = browserTest.extend<{ reusedContext: (options?: BrowserContextOptions) => Promise }>({ reusedContext: async ({ browserType, browser }, use) => { - await use(async () => { + await use(async (options: BrowserContextOptions = {}) => { const defaultContextOptions = (browserType as any)._defaultContextOptions; - const context = await (browser as any)._newContextForReuse(defaultContextOptions); + const context = await (browser as any)._newContextForReuse({ + ...defaultContextOptions, + ...options, + }); return context; }); }, @@ -235,6 +238,33 @@ test('should reset mouse position', async ({ reusedContext, browserName, platfor await expect(page.locator('#two')).toHaveCSS('background-color', 'rgb(0, 0, 255)'); }); +test('should reset Origin Private File System', async ({ reusedContext, httpsServer, browserName }) => { + test.skip(browserName === 'webkit', 'getDirectory is not supported in ephemeral context in WebKit https://github.com/microsoft/playwright/issues/18235#issuecomment-1289792576'); + test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/29901' }); + + let context = await reusedContext({ ignoreHTTPSErrors: true }); + let page = await context.newPage(); + await page.goto(httpsServer.EMPTY_PAGE); + await page.evaluate(async () => { + const root = await navigator.storage.getDirectory(); + await root.getDirectoryHandle('someDirectoryName', { create: true }); + await root.getFileHandle('foo.txt', { create: true }); + }); + + context = await reusedContext({ ignoreHTTPSErrors: true }); + page = await context.newPage(); + await page.goto(httpsServer.EMPTY_PAGE); + const { directoryExits, fileExits } = await page.evaluate(async () => { + const root = await navigator.storage.getDirectory(); + let directoryExits = true, fileExits = true; + await root.getDirectoryHandle('someDirectoryName').catch(() => { directoryExits = false; }); + await root.getFileHandle('foo.txt').catch(() => { fileExits = false; }); + return { directoryExits, fileExits }; + }); + expect(directoryExits).toBe(false); + expect(fileExits).toBe(false); +}); + test('should reset tracing', async ({ reusedContext, trace }, testInfo) => { test.skip(trace === 'on'); diff --git a/tests/playwright-test/playwright.reuse.spec.ts b/tests/playwright-test/playwright.reuse.spec.ts index 67a02613c5..799b6fa3d7 100644 --- a/tests/playwright-test/playwright.reuse.spec.ts +++ b/tests/playwright-test/playwright.reuse.spec.ts @@ -212,7 +212,7 @@ test('should clean storage', async ({ runInlineTest }) => { let lastContextGuid; test.beforeEach(async ({ page }) => { - await page.route('**/*', route => route.fulfill('')); + await page.route('**/*', route => route.fulfill({ body: '', contentType: 'text/html' })); await page.goto('http://example.com'); }); @@ -273,7 +273,7 @@ test('should restore localStorage', async ({ runInlineTest }) => { }); test.beforeEach(async ({ page }) => { - await page.route('**/*', route => route.fulfill('')); + await page.route('**/*', route => route.fulfill({ body: '', contentType: 'text/html' })); await page.goto('http://example.com'); }); @@ -330,7 +330,7 @@ test('should clean db', async ({ runInlineTest }) => { let lastContextGuid; test.beforeEach(async ({ page }) => { - await page.route('**/*', route => route.fulfill('')); + await page.route('**/*', route => route.fulfill({ body: '', contentType: 'text/html' })); await page.goto('http://example.com'); }); @@ -380,7 +380,7 @@ test('should restore cookies', async ({ runInlineTest }) => { }); test.beforeEach(async ({ page }) => { - await page.route('**/*', route => route.fulfill('')); + await page.route('**/*', route => route.fulfill({ body: '', contentType: 'text/html' })); await page.goto('http://example.com'); });