mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
revert(20509, 20596): expect.toPass is broken with these (#22254)
Reverts https://github.com/microsoft/playwright/pull/20509 and https://github.com/microsoft/playwright/pull/20596 Fixes #22215
This commit is contained in:
parent
1e9668f8bd
commit
c5aeab4d7e
@ -19,8 +19,6 @@ import type { FrameExpectOptions } from 'playwright-core/lib/client/types';
|
|||||||
import { colors } from 'playwright-core/lib/utilsBundle';
|
import { colors } from 'playwright-core/lib/utilsBundle';
|
||||||
import type { Expect } from '../../types/test';
|
import type { Expect } from '../../types/test';
|
||||||
import { expectTypes, callLogText } from '../util';
|
import { expectTypes, callLogText } from '../util';
|
||||||
import { currentTestInfo } from '../common/globals';
|
|
||||||
import type { TestInfoErrorState } from '../worker/testInfo';
|
|
||||||
import { toBeTruthy } from './toBeTruthy';
|
import { toBeTruthy } from './toBeTruthy';
|
||||||
import { toEqual } from './toEqual';
|
import { toEqual } from './toEqual';
|
||||||
import { toExpectedTextValues, toMatchText } from './toMatchText';
|
import { toExpectedTextValues, toMatchText } from './toMatchText';
|
||||||
@ -339,22 +337,11 @@ export async function toPass(
|
|||||||
timeout?: number,
|
timeout?: number,
|
||||||
} = {},
|
} = {},
|
||||||
) {
|
) {
|
||||||
const testInfo = currentTestInfo();
|
|
||||||
|
|
||||||
const timeout = options.timeout !== undefined ? options.timeout : 0;
|
const timeout = options.timeout !== undefined ? options.timeout : 0;
|
||||||
|
|
||||||
// Soft expects might mark test as failing.
|
|
||||||
// We want to revert this later if the matcher is actually passing.
|
|
||||||
// See https://github.com/microsoft/playwright/issues/20437
|
|
||||||
let testStateBeforeToPassMatcher: undefined|TestInfoErrorState;
|
|
||||||
const result = await pollAgainstTimeout<Error|undefined>(async () => {
|
const result = await pollAgainstTimeout<Error|undefined>(async () => {
|
||||||
try {
|
try {
|
||||||
if (testStateBeforeToPassMatcher && testInfo)
|
|
||||||
testInfo._restoreErrorState(testStateBeforeToPassMatcher);
|
|
||||||
testStateBeforeToPassMatcher = testInfo?._saveErrorState();
|
|
||||||
await callback();
|
await callback();
|
||||||
if (testInfo && testStateBeforeToPassMatcher && testInfo.errors.length > testStateBeforeToPassMatcher.errors.length)
|
|
||||||
return { continuePolling: !this.isNot, result: testInfo.errors[testInfo.errors.length - 1] };
|
|
||||||
return { continuePolling: this.isNot, result: undefined };
|
return { continuePolling: this.isNot, result: undefined };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return { continuePolling: !this.isNot, result: e };
|
return { continuePolling: !this.isNot, result: e };
|
||||||
@ -372,7 +359,5 @@ export async function toPass(
|
|||||||
|
|
||||||
return { message, pass: this.isNot };
|
return { message, pass: this.isNot };
|
||||||
}
|
}
|
||||||
if (testStateBeforeToPassMatcher && testInfo)
|
|
||||||
testInfo._restoreErrorState(testStateBeforeToPassMatcher);
|
|
||||||
return { pass: !this.isNot, message: () => '' };
|
return { pass: !this.isNot, message: () => '' };
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,6 @@ import type { Location } from '../../types/testReporter';
|
|||||||
import { getContainedPath, normalizeAndSaveAttachment, sanitizeForFilePath, serializeError, trimLongString } from '../util';
|
import { getContainedPath, normalizeAndSaveAttachment, sanitizeForFilePath, serializeError, trimLongString } from '../util';
|
||||||
import type * as trace from '@trace/trace';
|
import type * as trace from '@trace/trace';
|
||||||
|
|
||||||
export type TestInfoErrorState = {
|
|
||||||
status: TestStatus,
|
|
||||||
errors: TestInfoError[],
|
|
||||||
hasHardError: boolean,
|
|
||||||
};
|
|
||||||
|
|
||||||
interface TestStepInternal {
|
interface TestStepInternal {
|
||||||
complete(result: { error?: Error | TestInfoError }): void;
|
complete(result: { error?: Error | TestInfoError }): void;
|
||||||
stepId: string;
|
stepId: string;
|
||||||
@ -291,20 +285,6 @@ export class TestInfoImpl implements TestInfo {
|
|||||||
this.errors.push(error);
|
this.errors.push(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
_saveErrorState(): TestInfoErrorState {
|
|
||||||
return {
|
|
||||||
hasHardError: this._hasHardError,
|
|
||||||
status: this.status,
|
|
||||||
errors: this.errors.slice(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_restoreErrorState(state: TestInfoErrorState) {
|
|
||||||
this.status = state.status;
|
|
||||||
this.errors = state.errors.slice();
|
|
||||||
this._hasHardError = state.hasHardError;
|
|
||||||
}
|
|
||||||
|
|
||||||
async _runAsStep<T>(cb: (step: TestStepInternal) => Promise<T>, stepInfo: Omit<TestStepInternal, 'complete' | 'wallTime' | 'parentStepId' | 'stepId'>): Promise<T> {
|
async _runAsStep<T>(cb: (step: TestStepInternal) => Promise<T>, stepInfo: Omit<TestStepInternal, 'complete' | 'wallTime' | 'parentStepId' | 'stepId'>): Promise<T> {
|
||||||
const step = this._addStep({ ...stepInfo, wallTime: Date.now() });
|
const step = this._addStep({ ...stepInfo, wallTime: Date.now() });
|
||||||
return await zones.run('stepZone', step, async () => {
|
return await zones.run('stepZone', step, async () => {
|
||||||
|
@ -35,17 +35,10 @@ test('should retry predicate', async ({ runInlineTest }) => {
|
|||||||
}).toPass();
|
}).toPass();
|
||||||
expect(i).toBe(3);
|
expect(i).toBe(3);
|
||||||
});
|
});
|
||||||
test('should retry expect.soft assertions', async () => {
|
|
||||||
let i = 0;
|
|
||||||
await test.expect(() => {
|
|
||||||
expect.soft(++i).toBe(3);
|
|
||||||
}).toPass();
|
|
||||||
expect(i).toBe(3);
|
|
||||||
});
|
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.passed).toBe(3);
|
expect(result.passed).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should respect timeout', async ({ runInlineTest }) => {
|
test('should respect timeout', async ({ runInlineTest }) => {
|
||||||
@ -159,74 +152,12 @@ test('should use custom message', async ({ runInlineTest }) => {
|
|||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should swallow all soft errors inside toPass matcher, if successful', async ({ runInlineTest }) => {
|
|
||||||
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/20437' });
|
|
||||||
|
|
||||||
const result = await runInlineTest({
|
|
||||||
'a.spec.ts': `
|
|
||||||
import { test, expect } from '@playwright/test';
|
|
||||||
test('should respect soft', async () => {
|
|
||||||
expect.soft('before-toPass').toBe('zzzz');
|
|
||||||
let i = 0;
|
|
||||||
await test.expect(() => {
|
|
||||||
++i;
|
|
||||||
expect.soft('inside-toPass-' + i).toBe('inside-toPass-2');
|
|
||||||
}).toPass({ timeout: 1000 });
|
|
||||||
expect.soft('after-toPass').toBe('zzzz');
|
|
||||||
});
|
|
||||||
`
|
|
||||||
});
|
|
||||||
expect(result.output).toContain('Received: "before-toPass"');
|
|
||||||
expect(result.output).toContain('Received: "after-toPass"');
|
|
||||||
expect(result.output).not.toContain('Received: "inside-toPass-1"');
|
|
||||||
expect(result.exitCode).toBe(1);
|
|
||||||
expect(result.failed).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should work with no.toPass and failing soft assertion', async ({ runInlineTest }) => {
|
|
||||||
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/20518' });
|
|
||||||
|
|
||||||
const result = await runInlineTest({
|
|
||||||
'a.spec.ts': `
|
|
||||||
import { test, expect } from '@playwright/test';
|
|
||||||
test('should work', async () => {
|
|
||||||
await test.expect(() => {
|
|
||||||
expect.soft(1).toBe(2);
|
|
||||||
}).not.toPass({ timeout: 1000 });
|
|
||||||
});
|
|
||||||
`
|
|
||||||
});
|
|
||||||
expect(result.exitCode).toBe(0);
|
|
||||||
expect(result.failed).toBe(0);
|
|
||||||
expect(result.passed).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should show only soft errors on last toPass pass', async ({ runInlineTest }) => {
|
|
||||||
const result = await runInlineTest({
|
|
||||||
'a.spec.ts': `
|
|
||||||
import { test, expect } from '@playwright/test';
|
|
||||||
test('should respect soft', async () => {
|
|
||||||
let i = 0;
|
|
||||||
await test.expect(() => {
|
|
||||||
++i;
|
|
||||||
expect.soft('inside-toPass-' + i).toBe('0');
|
|
||||||
}).toPass({ timeout: 1000, intervals: [100, 100, 100000] });
|
|
||||||
});
|
|
||||||
`
|
|
||||||
});
|
|
||||||
expect(result.output).not.toContain('Received: "inside-toPass-1"');
|
|
||||||
expect(result.output).not.toContain('Received: "inside-toPass-2"');
|
|
||||||
expect(result.output).toContain('Received: "inside-toPass-3"');
|
|
||||||
expect(result.exitCode).toBe(1);
|
|
||||||
expect(result.failed).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should work with soft', async ({ runInlineTest }) => {
|
test('should work with soft', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'a.spec.ts': `
|
'a.spec.ts': `
|
||||||
import { test, expect } from '@playwright/test';
|
import { test, expect } from '@playwright/test';
|
||||||
test('should respect soft', async () => {
|
test('should respect soft', async () => {
|
||||||
await test.expect.soft(() => {
|
await expect.soft(() => {
|
||||||
expect(1).toBe(3);
|
expect(1).toBe(3);
|
||||||
}).toPass({ timeout: 1000 });
|
}).toPass({ timeout: 1000 });
|
||||||
expect.soft(2).toBe(3);
|
expect.soft(2).toBe(3);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user