diff --git a/packages/html-reporter/src/filter.ts b/packages/html-reporter/src/filter.ts index b0e8e4645042d..61713fd181cfd 100644 --- a/packages/html-reporter/src/filter.ts +++ b/packages/html-reporter/src/filter.ts @@ -84,7 +84,7 @@ export class Filter { token.push(c); continue; } - if (c === ' ' || c === ':') { + if (c === ' ') { if (token.length) { result.push(token.join('').toLowerCase()); token = []; @@ -108,9 +108,11 @@ export class Filter { if (test.outcome === 'skipped') status = 'skipped'; const searchValues: SearchValues = { - text: (status + ' ' + test.projectName + ' ' + test.location.file + ' ' + test.location.line + ' ' + test.path.join(' ') + ' ' + test.title).toLowerCase(), + text: (status + ' ' + test.projectName + ' ' + test.location.file + ' ' + test.path.join(' ') + ' ' + test.title).toLowerCase(), project: test.projectName.toLowerCase(), status: status as any, + file: test.location.file, + line: String(test.location.line), }; (test as any).searchValues = searchValues; } @@ -127,9 +129,14 @@ export class Filter { return false; } if (this.text.length) { - const matches = this.text.filter(t => searchValues.text.includes(t)).length === this.text.length; - if (!matches) + for (const text of this.text) { + if (searchValues.text.includes(text)) + continue; + const location = text.split(':'); + if (location.length === 2 && searchValues.file.includes(location[0]) && searchValues.line.includes(location[1])) + continue; return false; + } } if (this.labels.length) { const matches = this.labels.every(l => searchValues.text?.match(new RegExp(`(\\s|^)${escapeRegExp(l)}(\\s|$)`, 'g'))); @@ -145,5 +152,7 @@ type SearchValues = { text: string; project: string; status: 'passed' | 'failed' | 'flaky' | 'skipped'; + file: string; + line: string; }; diff --git a/tests/playwright-test/reporter-html.spec.ts b/tests/playwright-test/reporter-html.spec.ts index 9ab49f9060dbf..0fa9e843fb029 100644 --- a/tests/playwright-test/reporter-html.spec.ts +++ b/tests/playwright-test/reporter-html.spec.ts @@ -1881,3 +1881,61 @@ test('should list tests in the right order', async ({ runInlineTest, showReport, /main › second › passes\d+m?ssecond.ts:5/, ]); }); + +test('tests should filter by file', async ({ runInlineTest, showReport, page }) => { + const result = await runInlineTest({ + 'file-a.test.js': ` + const { test } = require('@playwright/test'); + test('a test 1', async ({}) => {}); + test('a test 2', async ({}) => {}); + `, + 'file-b.test.js': ` + const { test } = require('@playwright/test'); + test('b test 1', async ({}) => {}); + test('b test 2', async ({}) => {}); + `, + }, { reporter: 'dot,html' }, { PW_TEST_HTML_REPORT_OPEN: 'never' }); + + expect(result.exitCode).toBe(0); + expect(result.passed).toBe(4); + expect(result.failed).toBe(0); + + await showReport(); + + const searchInput = page.locator('.subnav-search-input'); + + await searchInput.fill('file-a'); + await expect(page.getByText('file-a.test.js', { exact: true })).toBeVisible(); + await expect(page.getByText('a test 1')).toBeVisible(); + await expect(page.getByText('a test 2')).toBeVisible(); + await expect(page.getByText('file-b.test.js', { exact: true })).not.toBeVisible(); + await expect(page.getByText('b test 1')).not.toBeVisible(); + await expect(page.getByText('b test 2')).not.toBeVisible(); + + await searchInput.fill('file-a:3'); + await expect(page.getByText('a test 1')).toBeVisible(); + await expect(page.getByText('a test 2')).not.toBeVisible(); +}); + +test('tests should filter by status', async ({ runInlineTest, showReport, page }) => { + const result = await runInlineTest({ + 'a.test.js': ` + const { test, expect } = require('@playwright/test'); + test('failed title', async ({}) => { expect(1).toBe(1); }); + test('passes title', async ({}) => { expect(1).toBe(2); }); + `, + }, { reporter: 'dot,html' }, { PW_TEST_HTML_REPORT_OPEN: 'never' }); + + expect(result.exitCode).toBe(1); + expect(result.passed).toBe(1); + expect(result.failed).toBe(1); + + await showReport(); + + const searchInput = page.locator('.subnav-search-input'); + + await searchInput.fill('s:failed'); + await expect(page.getByText('a.test.js', { exact: true })).toBeVisible(); + await expect(page.getByText('failed title')).not.toBeVisible(); + await expect(page.getByText('passes title')).toBeVisible(); +});