feat: print response text when toBeOK fails (#16040)

This commit is contained in:
Yury Semikhatsky 2022-07-29 11:46:48 -07:00 коммит произвёл GitHub
Родитель 4a47e275c8
Коммит af8e3e7afa
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 98 добавлений и 6 удалений

Просмотреть файл

@ -28,6 +28,7 @@
"./lib/utils/httpServer": "./lib/utils/httpServer.js",
"./lib/utils/hostPlatform": "./lib/utils/hostPlatform.js",
"./lib/utils/manualPromise": "./lib/utils/manualPromise.js",
"./lib/utils/mimeType": "./lib/utils/mimeType.js",
"./lib/utils/multimap": "./lib/utils/multimap.js",
"./lib/utils/processLauncher": "./lib/utils/processLauncher.js",
"./lib/utils/processLauncherCleanupEntrypoint": "./lib/utils/processLauncherCleanupEntrypoint.js",

Просмотреть файл

@ -31,6 +31,7 @@ import { getPlaywrightVersion } from '../../common/userAgent';
import { urlMatches } from '../../common/netUtils';
import { Frame } from '../frames';
import type { LifecycleEvent } from '../types';
import { isTextualMimeType } from '../../utils/mimeType';
const FALLBACK_HTTP_VERSION = 'HTTP/1.1';
@ -599,7 +600,3 @@ function parseCookie(c: string): har.Cookie {
}
return cookie;
}
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=.*)?$/);
}

Просмотреть файл

@ -0,0 +1,19 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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=.*)?$/);
}

Просмотреть файл

@ -16,6 +16,7 @@
import type { Locator, Page, APIResponse } from 'playwright-core';
import type { FrameExpectOptions } from 'playwright-core/lib/client/types';
import { colors } from 'playwright-core/lib/utilsBundle';
import { constructURLBasedOnBaseURL } from 'playwright-core/lib/utils';
import type { Expect } from '../types';
import { expectTypes, callLogText } from '../util';
@ -23,6 +24,7 @@ import { toBeTruthy } from './toBeTruthy';
import { toEqual } from './toEqual';
import { toExpectedTextValues, toMatchText } from './toMatchText';
import type { ParsedStackTrace } from 'playwright-core/lib/utils/stackTrace';
import { isTextualMimeType } from 'playwright-core/lib/utils/mimeType';
interface LocatorEx extends Locator {
_expect(customStackTrace: ParsedStackTrace, expression: string, options: Omit<FrameExpectOptions, 'expectedValue'> & { expectedValue?: any }): Promise<{ matches: boolean, received?: any, log?: string[] }>;
@ -289,8 +291,18 @@ export async function toBeOK(
) {
const matcherName = 'toBeOK';
expectTypes(response, ['APIResponse'], matcherName);
const log = (this.isNot === response.ok()) ? await response._fetchLog() : [];
const message = () => this.utils.matcherHint(matcherName, undefined, '', { isNot: this.isNot }) + callLogText(log);
const contentType = response.headers()['content-type'];
const isTextEncoding = contentType && isTextualMimeType(contentType);
const [log, text] = (this.isNot === response.ok()) ? await Promise.all([
response._fetchLog(),
isTextEncoding ? response.text() : null
]) : [];
const message = () => this.utils.matcherHint(matcherName, undefined, '', { isNot: this.isNot }) +
callLogText(log) +
(text === null ? '' : `\nResponse text:\n${colors.dim(text?.substring(0, 1000) || '')}`);
const pass = response.ok();
return { message, pass };
}

Просмотреть файл

@ -417,3 +417,65 @@ test('should support toBeOK', async ({ runInlineTest, server }) => {
expect(result.output).toContain(`← 404 Not Found`);
expect(result.output).toContain(`Error: toBeOK can be only used with APIResponse object`);
});
test('should print response text if toBeOK fails', async ({ runInlineTest, server }) => {
const result = await runInlineTest({
'a.test.ts': `
const { test } = pwt;
test('fail', async ({ page }) => {
const res = await page.request.get('${server.PREFIX}/unknown');
await expect(res).toBeOK();
});
`,
}, { workers: 1 });
expect(result.failed).toBe(1);
expect(result.exitCode).toBe(1);
expect(result.output).toContain(`→ GET ${server.PREFIX}/unknown`);
expect(result.output).toContain(`← 404 Not Found`);
expect(result.output).toContain(`Response text:`);
expect(result.output).toContain(`File not found`);
});
test('should only print response with text content type if toBeOK fails', async ({ runInlineTest, server }) => {
server.setRoute('/text-content-type', (req, res) => {
res.statusCode = 404;
res.setHeader('Content-type', 'text/plain');
res.end('Text error');
});
server.setRoute('/no-content-type', (req, res) => {
res.statusCode = 404;
res.end('No content type error');
});
server.setRoute('/binary-content-type', (req, res) => {
res.statusCode = 404;
res.setHeader('Content-type', 'image/bmp');
res.end('Image content type error');
});
const result = await runInlineTest({
'a.test.ts': `
const { test } = pwt;
test('text content type', async ({ page }) => {
const res = await page.request.get('${server.PREFIX}/text-content-type');
await expect(res).toBeOK();
});
test('no content type', async ({ page }) => {
const res = await page.request.get('${server.PREFIX}/no-content-type');
await expect(res).toBeOK();
});
test('image content type', async ({ page }) => {
const res = await page.request.get('${server.PREFIX}/image-content-type');
await expect(res).toBeOK();
});
`,
}, { workers: 1 });
expect(result.failed).toBe(3);
expect(result.exitCode).toBe(1);
expect(result.output).toContain(`← 404 Not Found`);
expect(result.output).toContain(`Text error`);
expect(result.output).not.toContain(`No content type error`);
expect(result.output).not.toContain(`Image content type error`);
});

Просмотреть файл

@ -307,6 +307,7 @@ class TestServer {
return;
if (err) {
response.statusCode = 404;
response.setHeader('Content-Type', 'text/plain');
response.end(`File not found: ${filePath}`);
return;
}