mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix(store): support text and binary values (#21006)
This commit is contained in:
parent
d12d35f124
commit
60e5a93832
@ -14,6 +14,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export function isJsonMimeType(mimeType: string) {
|
||||||
|
return !!mimeType.match(/^(application\/json|application\/.*?\+json|text\/(x-)?json)(;\s*charset=.*)?$/);
|
||||||
|
}
|
||||||
|
|
||||||
export function isTextualMimeType(mimeType: string) {
|
export function isTextualMimeType(mimeType: string) {
|
||||||
return !!mimeType.match(/^(text\/.*?|application\/(json|(x-)?javascript|xml.*?|ecmascript|graphql|x-www-form-urlencoded)|image\/svg(\+xml)?|application\/.*?(\+json|\+xml))(;\s*charset=.*)?$/);
|
return !!mimeType.match(/^(text\/.*?|application\/(json|(x-)?javascript|xml.*?|ecmascript|graphql|x-www-form-urlencoded)|image\/svg(\+xml)?|application\/.*?(\+json|\+xml))(;\s*charset=.*)?$/);
|
||||||
}
|
}
|
||||||
@ -18,6 +18,8 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import type { TestStore } from '../types/test';
|
import type { TestStore } from '../types/test';
|
||||||
import { currentConfig } from './common/globals';
|
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 implements TestStore {
|
||||||
async delete(name: string) {
|
async delete(name: string) {
|
||||||
@ -28,8 +30,13 @@ class JsonStore implements TestStore {
|
|||||||
async get<T>(name: string) {
|
async get<T>(name: string) {
|
||||||
const file = this.path(name);
|
const file = this.path(name);
|
||||||
try {
|
try {
|
||||||
const data = await fs.promises.readFile(file, 'utf-8');
|
const type = contentType(name);
|
||||||
return JSON.parse(data) as T;
|
if (type === 'binary')
|
||||||
|
return await fs.promises.readFile(file) as T;
|
||||||
|
const text = await fs.promises.readFile(file, 'utf-8');
|
||||||
|
if (type === 'json')
|
||||||
|
return JSON.parse(text) as T;
|
||||||
|
return text as T;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -52,10 +59,39 @@ class JsonStore implements TestStore {
|
|||||||
await fs.promises.rm(file, { force: true });
|
await fs.promises.rm(file, { force: true });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data = JSON.stringify(value, undefined, 2);
|
let data: string | Buffer = '';
|
||||||
|
switch (contentType(name)) {
|
||||||
|
case 'json': {
|
||||||
|
if (Buffer.isBuffer(value))
|
||||||
|
throw new Error('JSON value must be an Object');
|
||||||
|
data = JSON.stringify(value, undefined, 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'text': {
|
||||||
|
if (!isString(value))
|
||||||
|
throw new Error('Textual value must be a string');
|
||||||
|
data = value as string;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'binary': {
|
||||||
|
if (!Buffer.isBuffer(value))
|
||||||
|
throw new Error('Binary value must be a Buffer');
|
||||||
|
data = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
await fs.promises.mkdir(path.dirname(file), { recursive: true });
|
await fs.promises.mkdir(path.dirname(file), { recursive: true });
|
||||||
await fs.promises.writeFile(file, data);
|
await fs.promises.writeFile(file, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function contentType(name: string): 'json'|'text'|'binary' {
|
||||||
|
const mimeType = mime.getType(path.basename(name)) ?? 'application/octet-string';
|
||||||
|
if (isJsonMimeType(mimeType))
|
||||||
|
return 'json';
|
||||||
|
if (isTextualMimeType(mimeType))
|
||||||
|
return 'text';
|
||||||
|
return 'binary';
|
||||||
|
}
|
||||||
|
|
||||||
export const store = new JsonStore();
|
export const store = new JsonStore();
|
||||||
|
|||||||
@ -27,15 +27,15 @@ test('should provide store fixture', async ({ runInlineTest }) => {
|
|||||||
import { test, store, expect } from '@playwright/test';
|
import { test, store, expect } from '@playwright/test';
|
||||||
test('should store number', async ({ }) => {
|
test('should store number', async ({ }) => {
|
||||||
expect(store).toBeTruthy();
|
expect(store).toBeTruthy();
|
||||||
expect(await store.get('number')).toBe(undefined);
|
expect(await store.get('number.json')).toBe(undefined);
|
||||||
await store.set('number', 2022)
|
await store.set('number.json', 2022)
|
||||||
expect(await store.get('number')).toBe(2022);
|
expect(await store.get('number.json')).toBe(2022);
|
||||||
});
|
});
|
||||||
test('should store object', async ({ }) => {
|
test('should store object', async ({ }) => {
|
||||||
expect(store).toBeTruthy();
|
expect(store).toBeTruthy();
|
||||||
expect(await store.get('object')).toBe(undefined);
|
expect(await store.get('object.json')).toBe(undefined);
|
||||||
await store.set('object', { 'a': 2022 })
|
await store.set('object.json', { 'a': 2022 })
|
||||||
expect(await store.get('object')).toEqual({ 'a': 2022 });
|
expect(await store.get('object.json')).toEqual({ 'a': 2022 });
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
}, { workers: 1 });
|
}, { workers: 1 });
|
||||||
@ -63,27 +63,27 @@ test('should share store state between project setup and tests', async ({ runInl
|
|||||||
'store.setup.ts': `
|
'store.setup.ts': `
|
||||||
import { test, store, expect } from '@playwright/test';
|
import { test, store, expect } from '@playwright/test';
|
||||||
test('should initialize store', async ({ }) => {
|
test('should initialize store', async ({ }) => {
|
||||||
expect(await store.get('number')).toBe(undefined);
|
expect(await store.get('number.json')).toBe(undefined);
|
||||||
await store.set('number', 2022)
|
await store.set('number.json', 2022)
|
||||||
expect(await store.get('number')).toBe(2022);
|
expect(await store.get('number.json')).toBe(2022);
|
||||||
|
|
||||||
expect(await store.get('object')).toBe(undefined);
|
expect(await store.get('object.json')).toBe(undefined);
|
||||||
await store.set('object', { 'a': 2022 })
|
await store.set('object.json', { 'a': 2022 })
|
||||||
expect(await store.get('object')).toEqual({ 'a': 2022 });
|
expect(await store.get('object.json')).toEqual({ 'a': 2022 });
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
'a.test.ts': `
|
'a.test.ts': `
|
||||||
import { test, store, expect } from '@playwright/test';
|
import { test, store, expect } from '@playwright/test';
|
||||||
test('should get data from setup', async ({ }) => {
|
test('should get data from setup', async ({ }) => {
|
||||||
expect(await store.get('number')).toBe(2022);
|
expect(await store.get('number.json')).toBe(2022);
|
||||||
expect(await store.get('object')).toEqual({ 'a': 2022 });
|
expect(await store.get('object.json')).toEqual({ 'a': 2022 });
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
'b.test.ts': `
|
'b.test.ts': `
|
||||||
import { test, store, expect } from '@playwright/test';
|
import { test, store, expect } from '@playwright/test';
|
||||||
test('should get data from setup', async ({ }) => {
|
test('should get data from setup', async ({ }) => {
|
||||||
expect(await store.get('number')).toBe(2022);
|
expect(await store.get('number.json')).toBe(2022);
|
||||||
expect(await store.get('object')).toEqual({ 'a': 2022 });
|
expect(await store.get('object.json')).toEqual({ 'a': 2022 });
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
}, { workers: 1 });
|
}, { workers: 1 });
|
||||||
@ -99,17 +99,17 @@ test('should persist store state between project runs', async ({ runInlineTest }
|
|||||||
'a.test.ts': `
|
'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 ({ }) => {
|
test('should have no data on first run', async ({ }) => {
|
||||||
expect(await store.get('number')).toBe(undefined);
|
expect(await store.get('number.json')).toBe(undefined);
|
||||||
await store.set('number', 2022)
|
await store.set('number.json', 2022)
|
||||||
expect(await store.get('object')).toBe(undefined);
|
expect(await store.get('object.json')).toBe(undefined);
|
||||||
await store.set('object', { 'a': 2022 })
|
await store.set('object.json', { 'a': 2022 })
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
'b.test.ts': `
|
'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 ({ }) => {
|
test('should get data from previous run', async ({ }) => {
|
||||||
expect(await store.get('number')).toBe(2022);
|
expect(await store.get('number.json')).toBe(2022);
|
||||||
expect(await store.get('object')).toEqual({ 'a': 2022 });
|
expect(await store.get('object.json')).toEqual({ 'a': 2022 });
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
@ -152,13 +152,13 @@ test('should load context storageState from store', async ({ runInlineTest, serv
|
|||||||
expect(await store.get('user')).toBe(undefined);
|
expect(await store.get('user')).toBe(undefined);
|
||||||
await page.goto('${server.PREFIX}/setcookie.html');
|
await page.goto('${server.PREFIX}/setcookie.html');
|
||||||
const state = await page.context().storageState();
|
const state = await page.context().storageState();
|
||||||
await store.set('user', state);
|
await store.set('user.json', state);
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
'a.test.ts': `
|
'a.test.ts': `
|
||||||
import { test, store, expect } from '@playwright/test';
|
import { test, store, expect } from '@playwright/test';
|
||||||
test.use({
|
test.use({
|
||||||
storageState: async ({}, use) => use(store.get('user'))
|
storageState: async ({}, use) => use(store.get('user.json'))
|
||||||
})
|
})
|
||||||
test('should get data from setup', async ({ page }) => {
|
test('should get data from setup', async ({ page }) => {
|
||||||
await page.goto('${server.EMPTY_PAGE}');
|
await page.goto('${server.EMPTY_PAGE}');
|
||||||
@ -290,3 +290,48 @@ test('should delete value', async ({ runInlineTest }) => {
|
|||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.passed).toBe(1);
|
expect(result.passed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should support text, json and binary values', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'a.test.ts': `
|
||||||
|
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 });
|
||||||
|
});
|
||||||
|
test('text', async ({ }) => {
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
}, { workers: 1 });
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
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';
|
||||||
|
test('json', async ({ }) => {
|
||||||
|
const buf = Buffer.alloc(5);
|
||||||
|
await store.set('key.json', buf);
|
||||||
|
});
|
||||||
|
test('text', async ({ }) => {
|
||||||
|
await store.set('key.txt', {});
|
||||||
|
});
|
||||||
|
test('binary', async ({ }) => {
|
||||||
|
await store.set('key.png', {});
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
}, { workers: 1 });
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
expect(result.failed).toBe(3);
|
||||||
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user