From 95e7d3aabc7771836c25450b4dadfbc8896f13d4 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Fri, 17 Mar 2023 11:50:44 -0700 Subject: [PATCH] chore: hide store from public (#21763) --- docs/src/test-api/class-testconfig.md | 17 -- docs/src/test-api/class-teststore.md | 76 -------- .../src/common/configLoader.ts | 2 +- packages/playwright-test/src/index.ts | 2 +- packages/playwright-test/src/store.ts | 3 +- packages/playwright-test/types/test.d.ts | 68 ------- tests/playwright-test/playwright.spec.ts | 4 +- tests/playwright-test/store.spec.ts | 174 +++++++++--------- utils/generate_types/overrides-test.d.ts | 6 - 9 files changed, 92 insertions(+), 260 deletions(-) delete mode 100644 docs/src/test-api/class-teststore.md diff --git a/docs/src/test-api/class-testconfig.md b/docs/src/test-api/class-testconfig.md index 498c323327..ab15bbda11 100644 --- a/docs/src/test-api/class-testconfig.md +++ b/docs/src/test-api/class-testconfig.md @@ -475,23 +475,6 @@ export default defineConfig({ }); ``` -## property: TestConfig.storeDir -* since: v1.32 -- type: ?<[string]> - -Directory where the values accessible via [TestStore] are persisted. All pahts in [TestStore] are relative to `storeDir`. Defaults to `./playwright`. - -**Usage** - -```js -// playwright.config.ts -import { defineConfig } from '@playwright/test'; - -export default defineConfig({ - storeDir: './playwright-store', -}); -``` - ## property: TestConfig.testDir * since: v1.10 - type: ?<[string]> diff --git a/docs/src/test-api/class-teststore.md b/docs/src/test-api/class-teststore.md deleted file mode 100644 index 72c0acb6d3..0000000000 --- a/docs/src/test-api/class-teststore.md +++ /dev/null @@ -1,76 +0,0 @@ -# class: TestStore -* since: v1.32 -* langs: js - -Playwright Test provides a global `store` object that can be used to read/write values on the filesystem. Each value is stored in its own file inside './playwright' directory, configurable with [`property: TestConfig.storeDir`]. - -```js -import { test, store } from '@playwright/test'; - -test('get user name', async ({ page, context }) => { - await page.goto('/'); - // Return mock user info from the store. - await page.route('**/info/user', route => route.fulfill({ path: store.path('mocks/user.json')})) - await page.getByText('My Profile'); - // Check that the name matches mock data. - await expect(page.getByLabel('Name')).toHaveText('John'); -}); -``` - -## async method: TestStore.delete -* since: v1.32 - -Delete named item from the store. Does nothing if the path is not in the store. - -### param: TestStore.delete.path -* since: v1.32 -- `path` <[string]> - -Item path. - -## async method: TestStore.get -* since: v1.32 -- returns: <[any]> - -Get named item from the store. Returns undefined if there is no value with given path. - -### param: TestStore.get.path -* since: v1.32 -- `path` <[string]> - -Item path. - -## method: TestStore.path -* since: v1.32 -- returns: <[string]> - -Returns absolute path of the corresponding store entry on the file system. - -### param: TestStore.path.path -* since: v1.32 -- `path` <[string]> - -Path of the item in the store. - -## method: TestStore.root -* since: v1.32 -- returns: <[string]> - -Returns absolute path of the store root directory. - -## async method: TestStore.set -* since: v1.32 - -Set value to the store. - -### param: TestStore.set.path -* since: v1.32 -- `path` <[string]> - -Item path. - -### param: TestStore.set.value -* since: v1.32 -- `value` <[any]> - -Item value. The value must be serializable to JSON. Passing `undefined` deletes the entry with given path. diff --git a/packages/playwright-test/src/common/configLoader.ts b/packages/playwright-test/src/common/configLoader.ts index b35810ebf7..024ca929c9 100644 --- a/packages/playwright-test/src/common/configLoader.ts +++ b/packages/playwright-test/src/common/configLoader.ts @@ -111,7 +111,7 @@ export class ConfigLoader { config.snapshotDir = path.resolve(configDir, config.snapshotDir); this._fullConfig._internal.configDir = configDir; - this._fullConfig._internal.storeDir = path.resolve(configDir, config.storeDir || 'playwright'); + this._fullConfig._internal.storeDir = path.resolve(configDir, (config as any)._storeDir || 'playwright'); this._fullConfig.configFile = configFile; this._fullConfig.rootDir = config.testDir || configDir; this._fullConfig._internal.globalOutputDir = takeFirst(config.outputDir, throwawayArtifactsPath, baseFullConfig._internal.globalOutputDir); diff --git a/packages/playwright-test/src/index.ts b/packages/playwright-test/src/index.ts index f85df8a9a8..f53478f261 100644 --- a/packages/playwright-test/src/index.ts +++ b/packages/playwright-test/src/index.ts @@ -25,7 +25,7 @@ import { rootTestType } from './common/testType'; import { type ContextReuseMode } from './common/types'; import { artifactsFolderName } from './isomorphic/folders'; export { expect } from './matchers/expect'; -export { store } from './store'; +export { store as _store } from './store'; export const _baseTest: TestType<{}, {}> = rootTestType.test; addInternalStackPrefix(path.dirname(require.resolve('../package.json'))); diff --git a/packages/playwright-test/src/store.ts b/packages/playwright-test/src/store.ts index 36eef5d8b3..d7bcddeae1 100644 --- a/packages/playwright-test/src/store.ts +++ b/packages/playwright-test/src/store.ts @@ -16,12 +16,11 @@ import fs from 'fs'; import path from 'path'; -import type { TestStore } from '../types/test'; import { currentConfig } from './common/globals'; import { mime } from 'playwright-core/lib/utilsBundle'; import { isJsonMimeType, isString, isTextualMimeType } from 'playwright-core/lib/utils'; -class JsonStore implements TestStore { +class JsonStore { async delete(name: string) { const file = this.path(name); await fs.promises.rm(file, { force: true }); diff --git a/packages/playwright-test/types/test.d.ts b/packages/playwright-test/types/test.d.ts index 581622b3e4..6f0cf3566d 100644 --- a/packages/playwright-test/types/test.d.ts +++ b/packages/playwright-test/types/test.d.ts @@ -1149,24 +1149,6 @@ interface TestConfig { */ snapshotPathTemplate?: string; - /** - * Directory where the values accessible via [TestStore] are persisted. All pahts in [TestStore] are relative to - * `storeDir`. Defaults to `./playwright`. - * - * **Usage** - * - * ```js - * // playwright.config.ts - * import { defineConfig } from '@playwright/test'; - * - * export default defineConfig({ - * storeDir: './playwright-store', - * }); - * ``` - * - */ - storeDir?: string; - /** * Directory that will be recursively scanned for test files. Defaults to the directory of the configuration file. * @@ -3318,55 +3300,6 @@ type ConnectOptions = { timeout?: number; }; -/** - * Playwright Test provides a global `store` object that can be used to read/write values on the filesystem. Each - * value is stored in its own file inside './playwright' directory, configurable with - * [testConfig.storeDir](https://playwright.dev/docs/api/class-testconfig#test-config-store-dir). - * - * ```js - * import { test, store } from '@playwright/test'; - * - * test('get user name', async ({ page, context }) => { - * await page.goto('/'); - * // Return mock user info from the store. - * await page.route('**\/info/user', route => route.fulfill({ path: store.path('mocks/user.json')})) - * await page.getByText('My Profile'); - * // Check that the name matches mock data. - * await expect(page.getByLabel('Name')).toHaveText('John'); - * }); - * ``` - * - */ -export interface TestStore { - /** - * Get named item from the store. Returns undefined if there is no value with given path. - * @param path Item path. - */ - get(path: string): Promise; - /** - * Set value to the store. - * @param path Item path. - * @param value Item value. The value must be serializable to JSON. Passing `undefined` deletes the entry with given path. - */ - set(path: string, value: T | undefined): Promise; - /** - * Delete named item from the store. Does nothing if the path is not in the store. - * @param path Item path. - */ - delete(path: string): Promise; - - /** - * Returns absolute path of the corresponding store entry on the file system. - * @param path Path of the item in the store. - */ - path(path: string): string; - - /** - * Returns absolute path of the store root directory. - */ - root(): string; -} - /** * Playwright Test provides many options to configure test environment, [Browser], [BrowserContext] and more. * @@ -4317,7 +4250,6 @@ export default test; export const _baseTest: TestType<{}, {}>; export const expect: Expect; -export const store: TestStore; /** * Defines Playwright config diff --git a/tests/playwright-test/playwright.spec.ts b/tests/playwright-test/playwright.spec.ts index 659f534815..e8423aa4d6 100644 --- a/tests/playwright-test/playwright.spec.ts +++ b/tests/playwright-test/playwright.spec.ts @@ -756,9 +756,9 @@ test('fulfill with return path of the entry', async ({ runInlineTest }) => { await fs.promises.writeFile(file, JSON.stringify({ 'a': 2023 })); const result = await runInlineTest({ 'a.test.ts': ` - import { test, store, expect } from '@playwright/test'; + import { test, _store, expect } from '@playwright/test'; test('should read value from path', async ({ page }) => { - await page.route('**/*', route => route.fulfill({ path: store.path('foo/body.json')})) + await page.route('**/*', route => route.fulfill({ path: _store.path('foo/body.json')})) await page.goto('http://example.com'); expect(await page.textContent('body')).toBe(JSON.stringify({ 'a': 2023 })) }); diff --git a/tests/playwright-test/store.spec.ts b/tests/playwright-test/store.spec.ts index 0de660f37d..ddf25638fa 100644 --- a/tests/playwright-test/store.spec.ts +++ b/tests/playwright-test/store.spec.ts @@ -18,24 +18,24 @@ import fs from 'fs'; import path from 'path'; import { expect, test } from './playwright-test-fixtures'; -test('should provide store fixture', async ({ runInlineTest }) => { +test('should provide _store fixture', async ({ runInlineTest }) => { const result = await runInlineTest({ 'playwright.config.js': ` module.exports = {}; `, 'a.test.ts': ` - import { test, store, expect } from '@playwright/test'; - test('should store number', async ({ }) => { - expect(store).toBeTruthy(); - expect(await store.get('number.json')).toBe(undefined); - await store.set('number.json', 2022) - expect(await store.get('number.json')).toBe(2022); + import { test, _store, expect } from '@playwright/test'; + test('should _store number', async ({ }) => { + expect(_store).toBeTruthy(); + expect(await _store.get('number.json')).toBe(undefined); + await _store.set('number.json', 2022) + expect(await _store.get('number.json')).toBe(2022); }); - test('should store object', async ({ }) => { - expect(store).toBeTruthy(); - expect(await store.get('object.json')).toBe(undefined); - await store.set('object.json', { 'a': 2022 }) - expect(await store.get('object.json')).toEqual({ 'a': 2022 }); + test('should _store object', async ({ }) => { + expect(_store).toBeTruthy(); + expect(await _store.get('object.json')).toBe(undefined); + await _store.set('object.json', { 'a': 2022 }) + expect(await _store.get('object.json')).toEqual({ 'a': 2022 }); }); `, }, { workers: 1 }); @@ -43,14 +43,14 @@ test('should provide store fixture', async ({ runInlineTest }) => { expect(result.passed).toBe(2); }); -test('should share store state between project setup and tests', async ({ runInlineTest }) => { +test('should share _store state between project setup and tests', async ({ runInlineTest }) => { const result = await runInlineTest({ 'playwright.config.js': ` module.exports = { projects: [ { name: 'p1', - testMatch: /.*store.setup.ts/ + testMatch: /.*_store.setup.ts/ }, { name: 'p2', @@ -60,30 +60,30 @@ test('should share store state between project setup and tests', async ({ runInl ] }; `, - 'store.setup.ts': ` - import { test, store, expect } from '@playwright/test'; - test('should initialize store', async ({ }) => { - expect(await store.get('number.json')).toBe(undefined); - await store.set('number.json', 2022) - expect(await store.get('number.json')).toBe(2022); + '_store.setup.ts': ` + import { test, _store, expect } from '@playwright/test'; + test('should initialize _store', async ({ }) => { + expect(await _store.get('number.json')).toBe(undefined); + await _store.set('number.json', 2022) + expect(await _store.get('number.json')).toBe(2022); - expect(await store.get('object.json')).toBe(undefined); - await store.set('object.json', { 'a': 2022 }) - expect(await store.get('object.json')).toEqual({ 'a': 2022 }); + expect(await _store.get('object.json')).toBe(undefined); + await _store.set('object.json', { 'a': 2022 }) + expect(await _store.get('object.json')).toEqual({ 'a': 2022 }); }); `, 'a.test.ts': ` - import { test, store, expect } from '@playwright/test'; + import { test, _store, expect } from '@playwright/test'; test('should get data from setup', async ({ }) => { - expect(await store.get('number.json')).toBe(2022); - expect(await store.get('object.json')).toEqual({ 'a': 2022 }); + expect(await _store.get('number.json')).toBe(2022); + expect(await _store.get('object.json')).toEqual({ 'a': 2022 }); }); `, 'b.test.ts': ` - import { test, store, expect } from '@playwright/test'; + import { test, _store, expect } from '@playwright/test'; test('should get data from setup', async ({ }) => { - expect(await store.get('number.json')).toBe(2022); - expect(await store.get('object.json')).toEqual({ 'a': 2022 }); + expect(await _store.get('number.json')).toBe(2022); + expect(await _store.get('object.json')).toEqual({ 'a': 2022 }); }); `, }, { workers: 1 }); @@ -91,25 +91,25 @@ test('should share store state between project setup and tests', async ({ runInl expect(result.passed).toBe(3); }); -test('should persist store state between project runs', async ({ runInlineTest }) => { +test('should persist _store state between project runs', async ({ runInlineTest }) => { const files = { 'playwright.config.js': ` module.exports = { }; `, 'a.test.ts': ` - import { test, store, expect } from '@playwright/test'; + import { test, _store, expect } from '@playwright/test'; test('should have no data on first run', async ({ }) => { - expect(await store.get('number.json')).toBe(undefined); - await store.set('number.json', 2022) - expect(await store.get('object.json')).toBe(undefined); - await store.set('object.json', { 'a': 2022 }) + expect(await _store.get('number.json')).toBe(undefined); + await _store.set('number.json', 2022) + expect(await _store.get('object.json')).toBe(undefined); + await _store.set('object.json', { 'a': 2022 }) }); `, 'b.test.ts': ` - import { test, store, expect } from '@playwright/test'; + import { test, _store, expect } from '@playwright/test'; test('should get data from previous run', async ({ }) => { - expect(await store.get('number.json')).toBe(2022); - expect(await store.get('object.json')).toEqual({ 'a': 2022 }); + expect(await _store.get('number.json')).toBe(2022); + expect(await _store.get('object.json')).toEqual({ 'a': 2022 }); }); `, }; @@ -125,7 +125,7 @@ test('should persist store state between project runs', async ({ runInlineTest } } }); -test('should load context storageState from store', async ({ runInlineTest, server }) => { +test('should load context storageState from _store', async ({ runInlineTest, server }) => { server.setRoute('/setcookie.html', (req, res) => { res.setHeader('Set-Cookie', ['a=v1']); res.end(); @@ -136,7 +136,7 @@ test('should load context storageState from store', async ({ runInlineTest, serv projects: [ { name: 'setup', - testMatch: /.*store.setup.ts/ + testMatch: /.*_store.setup.ts/ }, { name: 'p2', @@ -146,19 +146,19 @@ test('should load context storageState from store', async ({ runInlineTest, serv ] }; `, - 'store.setup.ts': ` - import { test, store, expect } from '@playwright/test'; + '_store.setup.ts': ` + import { test, _store, expect } from '@playwright/test'; test('should save storageState', async ({ page, context }) => { - expect(await store.get('user')).toBe(undefined); + expect(await _store.get('user')).toBe(undefined); await page.goto('${server.PREFIX}/setcookie.html'); const state = await page.context().storageState(); - await store.set('user.json', state); + await _store.set('user.json', state); }); `, 'a.test.ts': ` - import { test, store, expect } from '@playwright/test'; + import { test, _store, expect } from '@playwright/test'; test.use({ - storageState: async ({}, use) => use(store.get('user.json')) + storageState: async ({}, use) => use(_store.get('user.json')) }) test('should get data from setup', async ({ page }) => { await page.goto('${server.EMPTY_PAGE}'); @@ -180,8 +180,8 @@ test('should load context storageState from store', async ({ runInlineTest, serv }); test('should load value from filesystem', async ({ runInlineTest }) => { - const storeDir = test.info().outputPath('playwright'); - const file = path.join(storeDir, 'foo/bar.json'); + const _storeDir = test.info().outputPath('playwright'); + const file = path.join(_storeDir, 'foo/bar.json'); await fs.promises.mkdir(path.dirname(file), { recursive: true }); await fs.promises.writeFile(file, JSON.stringify({ 'a': 2023 })); const result = await runInlineTest({ @@ -189,9 +189,9 @@ test('should load value from filesystem', async ({ runInlineTest }) => { module.exports = {}; `, 'a.test.ts': ` - import { test, store, expect } from '@playwright/test'; - test('should store number', async ({ }) => { - expect(await store.get('foo/bar.json')).toEqual({ 'a': 2023 }); + import { test, _store, expect } from '@playwright/test'; + test('should _store number', async ({ }) => { + expect(await _store.get('foo/bar.json')).toEqual({ 'a': 2023 }); }); `, }, { workers: 1 }); @@ -200,15 +200,15 @@ test('should load value from filesystem', async ({ runInlineTest }) => { }); test('should return root path', async ({ runInlineTest }) => { - const storeDir = test.info().outputPath('playwright'); + const _storeDir = test.info().outputPath('playwright'); const result = await runInlineTest({ 'playwright.config.js': ` module.exports = {}; `, 'a.test.ts': ` - import { test, store, expect } from '@playwright/test'; - test('should store number', async ({ }) => { - expect(store.root()).toBe('${storeDir.replace(/\\/g, '\\\\')}'); + import { test, _store, expect } from '@playwright/test'; + test('should _store number', async ({ }) => { + expect(_store.root()).toBe('${_storeDir.replace(/\\/g, '\\\\')}'); }); `, }, { workers: 1 }); @@ -226,24 +226,24 @@ test('should work in global setup and teardown', async ({ runInlineTest }) => { }; `, 'globalSetup.ts': ` - import { store, expect } from '@playwright/test'; + import { _store, expect } from '@playwright/test'; module.exports = async () => { - expect(store).toBeTruthy(); - await store.set('foo/bar.json', {'a': 2023}); + expect(_store).toBeTruthy(); + await _store.set('foo/bar.json', {'a': 2023}); }; `, 'globalTeardown.ts': ` - import { store, expect } from '@playwright/test'; + import { _store, expect } from '@playwright/test'; module.exports = async () => { - const val = await store.get('foo/bar.json'); + const val = await _store.get('foo/bar.json'); console.log('teardown=' + val); }; `, 'a.test.ts': ` - import { test, store, expect } from '@playwright/test'; + import { test, _store, expect } from '@playwright/test'; test('should read value from global setup', async ({ }) => { - expect(await store.get('foo/bar.json')).toEqual({ 'a': 2023 }); - await store.set('foo/bar.json', 'from test'); + expect(await _store.get('foo/bar.json')).toEqual({ 'a': 2023 }); + await _store.set('foo/bar.json', 'from test'); }); `, }, { workers: 1 }); @@ -251,39 +251,39 @@ test('should work in global setup and teardown', async ({ runInlineTest }) => { expect(result.passed).toBe(1); }); -test('store root can be changed with TestConfig.storeDir', async ({ runInlineTest }) => { +test('_store root can be changed with TestConfig._storeDir', async ({ runInlineTest }) => { const result = await runInlineTest({ 'playwright.config.ts': ` import * as path from 'path'; module.exports = { - storeDir: 'my/store/dir', + _storeDir: 'my/_store/dir', }; `, 'a.test.ts': ` - import { test, store, expect } from '@playwright/test'; - test('should store value', async ({ }) => { - await store.set('foo/bar.json', {'a': 2023}); + import { test, _store, expect } from '@playwright/test'; + test('should _store value', async ({ }) => { + await _store.set('foo/bar.json', {'a': 2023}); }); test('should read value', async ({ }) => { - expect(await store.get('foo/bar.json')).toEqual({ 'a': 2023 }); + expect(await _store.get('foo/bar.json')).toEqual({ 'a': 2023 }); }); `, }, { workers: 1 }); expect(result.exitCode).toBe(0); expect(result.passed).toBe(2); - const file = path.join(test.info().outputPath(), 'my/store/dir/foo/bar.json'); + const file = path.join(test.info().outputPath(), 'my/_store/dir/foo/bar.json'); expect(JSON.parse(await fs.promises.readFile(file, 'utf-8'))).toEqual({ 'a': 2023 }); }); test('should delete value', async ({ runInlineTest }) => { const result = await runInlineTest({ 'a.test.ts': ` - import { test, store, expect } from '@playwright/test'; - test('should store value', async ({ }) => { - await store.set('foo/bar.json', {'a': 2023}); - expect(await store.get('foo/bar.json')).toEqual({ 'a': 2023 }); - await store.delete('foo/bar.json'); - expect(await store.get('foo/bar.json')).toBe(undefined); + import { test, _store, expect } from '@playwright/test'; + test('should _store value', async ({ }) => { + await _store.set('foo/bar.json', {'a': 2023}); + expect(await _store.get('foo/bar.json')).toEqual({ 'a': 2023 }); + await _store.delete('foo/bar.json'); + expect(await _store.get('foo/bar.json')).toBe(undefined); }); `, }, { workers: 1 }); @@ -294,21 +294,21 @@ test('should delete value', async ({ runInlineTest }) => { test('should support text, json and binary values', async ({ runInlineTest }) => { const result = await runInlineTest({ 'a.test.ts': ` - import { test, store, expect } from '@playwright/test'; + import { test, _store, expect } from '@playwright/test'; test('json', async ({ }) => { - await store.set('key.json', {'a': 2023}); - expect(await store.get('key.json')).toEqual({ 'a': 2023 }); + await _store.set('key.json', {'a': 2023}); + expect(await _store.get('key.json')).toEqual({ 'a': 2023 }); }); test('text', async ({ }) => { - await store.set('key.txt', 'Hello'); - expect(await store.get('key.txt')).toEqual('Hello'); + await _store.set('key.txt', 'Hello'); + expect(await _store.get('key.txt')).toEqual('Hello'); }); test('binary', async ({ }) => { const buf = Buffer.alloc(256); for (let i = 0; i < 256; i++) buf[i] = i; - await store.set('key.png', buf); - expect(await store.get('key.png')).toEqual(buf); + await _store.set('key.png', buf); + expect(await _store.get('key.png')).toEqual(buf); }); `, }, { workers: 1 }); @@ -319,16 +319,16 @@ test('should support text, json and binary values', async ({ runInlineTest }) => test('should throw on unsupported value type for given key extension', async ({ runInlineTest }) => { const result = await runInlineTest({ 'a.test.ts': ` - import { test, store, expect } from '@playwright/test'; + import { test, _store, expect } from '@playwright/test'; test('json', async ({ }) => { const buf = Buffer.alloc(5); - await store.set('key.json', buf); + await _store.set('key.json', buf); }); test('text', async ({ }) => { - await store.set('key.txt', {}); + await _store.set('key.txt', {}); }); test('binary', async ({ }) => { - await store.set('key.png', {}); + await _store.set('key.png', {}); }); `, }, { workers: 1 }); diff --git a/utils/generate_types/overrides-test.d.ts b/utils/generate_types/overrides-test.d.ts index d441b59594..81fa59f62d 100644 --- a/utils/generate_types/overrides-test.d.ts +++ b/utils/generate_types/overrides-test.d.ts @@ -197,11 +197,6 @@ type ConnectOptions = { timeout?: number; }; -export interface TestStore { - get(path: string): Promise; - set(path: string, value: T | undefined): Promise; -} - export interface PlaywrightWorkerOptions { browserName: BrowserName; defaultBrowserType: BrowserName; @@ -376,7 +371,6 @@ export default test; export const _baseTest: TestType<{}, {}>; export const expect: Expect; -export const store: TestStore; /** * Defines Playwright config