chore: move multi-select assertion to toHaveValues (#14595)
Follow-up to e0a87e52d7
This commit is contained in:
parent
dbc2494e54
commit
978854b859
|
|
@ -293,13 +293,25 @@ Whether to use `element.innerText` instead of `element.textContent` when retriev
|
|||
The opposite of [`method: LocatorAssertions.toHaveValue`].
|
||||
|
||||
### param: LocatorAssertions.NotToHaveValue.value
|
||||
- `value` <[string]|[RegExp]|[Array]<[string]|[RegExp]>>
|
||||
- `value` <[string]|[RegExp]>
|
||||
|
||||
Expected value. A list of expected values can be used if the Locator is a `select` element with the `multiple` attribute.
|
||||
Expected value.
|
||||
|
||||
### option: LocatorAssertions.NotToHaveValue.timeout = %%-js-assertions-timeout-%%
|
||||
### option: LocatorAssertions.NotToHaveValue.timeout = %%-csharp-java-python-assertions-timeout-%%
|
||||
|
||||
## async method: LocatorAssertions.NotToHaveValues
|
||||
* langs: python
|
||||
|
||||
The opposite of [`method: LocatorAssertions.toHaveValues`].
|
||||
|
||||
### param: LocatorAssertions.NotToHaveValues.values
|
||||
- `values` <[Array]<[string]|[RegExp]>>
|
||||
|
||||
Expected options currently selected.
|
||||
|
||||
### option: LocatorAssertions.NotToHaveValues.timeout = %%-js-assertions-timeout-%%
|
||||
### option: LocatorAssertions.NotToHaveValues.timeout = %%-csharp-java-python-assertions-timeout-%%
|
||||
|
||||
## async method: LocatorAssertions.toBeChecked
|
||||
* langs:
|
||||
|
|
@ -1201,9 +1213,68 @@ await Expect(locator).ToHaveValueAsync(new Regex("[0-9]"));
|
|||
```
|
||||
|
||||
### param: LocatorAssertions.toHaveValue.value
|
||||
- `value` <[string]|[RegExp]|[Array]<[string]|[RegExp]>>
|
||||
- `value` <[string]|[RegExp]>
|
||||
|
||||
Expected value. A list of expected values can be used if the Locator is a `select` element with the `multiple` attribute.
|
||||
Expected value.
|
||||
|
||||
### option: LocatorAssertions.toHaveValue.timeout = %%-js-assertions-timeout-%%
|
||||
### option: LocatorAssertions.toHaveValue.timeout = %%-csharp-java-python-assertions-timeout-%%
|
||||
|
||||
## async method: LocatorAssertions.toHaveValues
|
||||
* langs:
|
||||
- alias-java: hasValues
|
||||
|
||||
Ensures the [Locator] points to multi-select/combobox (i.e. a `select` with the `multiple` attribute) and the specified values are selected.
|
||||
|
||||
For example, given the following element:
|
||||
|
||||
```html
|
||||
<select id="favorite-colors" multiple>
|
||||
<option value="R">Red</option>
|
||||
<option value="G">Green</option>
|
||||
<option value="B">Blue</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
```js
|
||||
const locator = page.locator("id=favorite-colors");
|
||||
await locator.selectOption(["R", "G"]);
|
||||
await expect(locator).toHaveValues([/R/, /G/]);
|
||||
```
|
||||
|
||||
```java
|
||||
page.locator("id=favorite-colors").selectOption(["R", "G"]);
|
||||
assertThat(page.locator("id=favorite-colors")).hasValues(new Pattern[] { Pattern.compile("R"), Pattern.compile("G") });
|
||||
```
|
||||
|
||||
```python async
|
||||
import re
|
||||
from playwright.async_api import expect
|
||||
|
||||
locator = page.locator("id=favorite-colors")
|
||||
await locator.select_option(["R", "G"])
|
||||
await expect(locator).to_have_values([re.compile(r"R"), re.compile(r"G")])
|
||||
```
|
||||
|
||||
```python sync
|
||||
import re
|
||||
from playwright.sync_api import expect
|
||||
|
||||
locator = page.locator("id=favorite-colors")
|
||||
locator.select_option(["R", "G"])
|
||||
expect(locator).to_have_values([re.compile(r"R"), re.compile(r"G")])
|
||||
```
|
||||
|
||||
```csharp
|
||||
var locator = Page.Locator("id=favorite-colors");
|
||||
await locator.SelectOptionAsync(new string[] { "R", "G" })
|
||||
await Expect(locator).ToHaveValuesAsync(new Regex[] { new Regex("R"), new Regex("G") });
|
||||
```
|
||||
|
||||
### param: LocatorAssertions.toHaveValues.values
|
||||
- `values` <[Array]<[string]|[RegExp]>>
|
||||
|
||||
Expected options currently selected.
|
||||
|
||||
### option: LocatorAssertions.toHaveValues.timeout = %%-js-assertions-timeout-%%
|
||||
### option: LocatorAssertions.toHaveValues.timeout = %%-csharp-java-python-assertions-timeout-%%
|
||||
|
|
|
|||
|
|
@ -1053,13 +1053,13 @@ export class InjectedScript {
|
|||
|
||||
// Multi-Select/Combobox
|
||||
{
|
||||
if (expression === 'to.have.value' && options.expectedText?.length && options.expectedText.length >= 2) {
|
||||
if (expression === 'to.have.values') {
|
||||
element = this.retarget(element, 'follow-label')!;
|
||||
if (element.nodeName !== 'SELECT' || !(element as HTMLSelectElement).multiple)
|
||||
throw this.createStacklessError('Not a select element with a multiple attribute');
|
||||
|
||||
const received = [...(element as HTMLSelectElement).selectedOptions].map(o => o.value);
|
||||
if (received.length !== options.expectedText.length)
|
||||
if (received.length !== options.expectedText!.length)
|
||||
return { received, matches: false };
|
||||
return { received, matches: received.map((r, i) => new ExpectedTextMatcher(options.expectedText![i]).matches(r)).every(Boolean) };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ import {
|
|||
toHaveText,
|
||||
toHaveTitle,
|
||||
toHaveURL,
|
||||
toHaveValue
|
||||
toHaveValue,
|
||||
toHaveValues,
|
||||
} from './matchers/matchers';
|
||||
import { toMatchSnapshot, toHaveScreenshot } from './matchers/toMatchSnapshot';
|
||||
import type { Expect } from './types';
|
||||
|
|
@ -141,6 +142,7 @@ const customMatchers = {
|
|||
toHaveTitle,
|
||||
toHaveURL,
|
||||
toHaveValue,
|
||||
toHaveValues,
|
||||
toMatchSnapshot,
|
||||
toHaveScreenshot,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -234,20 +234,25 @@ export function toHaveText(
|
|||
export function toHaveValue(
|
||||
this: ReturnType<Expect['getState']>,
|
||||
locator: LocatorEx,
|
||||
expected: string | RegExp | (string | RegExp)[],
|
||||
expected: string | RegExp,
|
||||
options?: { timeout?: number },
|
||||
) {
|
||||
if (Array.isArray(expected)) {
|
||||
return toEqual.call(this, 'toHaveValue', locator, 'Locator', async (isNot, timeout, customStackTrace) => {
|
||||
const expectedText = toExpectedTextValues(expected);
|
||||
return await locator._expect(customStackTrace, 'to.have.value', { expectedText, isNot, timeout });
|
||||
}, expected, options);
|
||||
} else {
|
||||
return toMatchText.call(this, 'toHaveValue', locator, 'Locator', async (isNot, timeout, customStackTrace) => {
|
||||
const expectedText = toExpectedTextValues([expected]);
|
||||
return await locator._expect(customStackTrace, 'to.have.value', { expectedText, isNot, timeout });
|
||||
}, expected, options);
|
||||
}
|
||||
return toMatchText.call(this, 'toHaveValue', locator, 'Locator', async (isNot, timeout, customStackTrace) => {
|
||||
const expectedText = toExpectedTextValues([expected]);
|
||||
return await locator._expect(customStackTrace, 'to.have.value', { expectedText, isNot, timeout });
|
||||
}, expected, options);
|
||||
}
|
||||
|
||||
export function toHaveValues(
|
||||
this: ReturnType<Expect['getState']>,
|
||||
locator: LocatorEx,
|
||||
expected: (string | RegExp)[],
|
||||
options?: { timeout?: number },
|
||||
) {
|
||||
return toEqual.call(this, 'toHaveValues', locator, 'Locator', async (isNot, timeout, customStackTrace) => {
|
||||
const expectedText = toExpectedTextValues(expected);
|
||||
return await locator._expect(customStackTrace, 'to.have.values', { expectedText, isNot, timeout });
|
||||
}, expected, options);
|
||||
}
|
||||
|
||||
export function toHaveTitle(
|
||||
|
|
|
|||
34
packages/playwright-test/types/test.d.ts
vendored
34
packages/playwright-test/types/test.d.ts
vendored
|
|
@ -3528,10 +3528,40 @@ interface LocatorAssertions {
|
|||
* await expect(locator).toHaveValue(/[0-9]/);
|
||||
* ```
|
||||
*
|
||||
* @param value Expected value. A list of expected values can be used if the Locator is a `select` element with the `multiple` attribute.
|
||||
* @param value Expected value.
|
||||
* @param options
|
||||
*/
|
||||
toHaveValue(value: string|RegExp|Array<string|RegExp>, options?: {
|
||||
toHaveValue(value: string|RegExp, options?: {
|
||||
/**
|
||||
* Time to retry the assertion for. Defaults to `timeout` in `TestConfig.expect`.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Ensures the [Locator] points to multi-select/combobox (i.e. a `select` with the `multiple` attribute) and the specified
|
||||
* values are selected.
|
||||
*
|
||||
* For example, given the following element:
|
||||
*
|
||||
* ```html
|
||||
* <select id="favorite-colors" multiple>
|
||||
* <option value="R">Red</option>
|
||||
* <option value="G">Green</option>
|
||||
* <option value="B">Blue</option>
|
||||
* </select>
|
||||
* ```
|
||||
*
|
||||
* ```js
|
||||
* const locator = page.locator("id=favorite-colors");
|
||||
* await locator.selectOption(["R", "G"]);
|
||||
* await expect(locator).toHaveValues([/R/, /G/]);
|
||||
* ```
|
||||
*
|
||||
* @param values Expected options currently selected.
|
||||
* @param options
|
||||
*/
|
||||
toHaveValues(values: Array<string|RegExp>, options?: {
|
||||
/**
|
||||
* Time to retry the assertion for. Defaults to `timeout` in `TestConfig.expect`.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ test('should support toHaveValue failing', async ({ runInlineTest }) => {
|
|||
expect(result.output).toContain('"Text content"');
|
||||
});
|
||||
|
||||
test.describe('should support toHaveValue with multi-select', () => {
|
||||
test.describe('should support toHaveValues with multi-select', () => {
|
||||
test('works with text', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
|
|
@ -428,7 +428,7 @@ test.describe('should support toHaveValue with multi-select', () => {
|
|||
\`);
|
||||
const locator = page.locator('select');
|
||||
await locator.selectOption(['R', 'G']);
|
||||
await expect(locator).toHaveValue(['R', 'G']);
|
||||
await expect(locator).toHaveValues(['R', 'G']);
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
|
|
@ -452,7 +452,7 @@ test.describe('should support toHaveValue with multi-select', () => {
|
|||
\`);
|
||||
const locator = page.locator('text=Pick a Color');
|
||||
await locator.selectOption(['R', 'G']);
|
||||
await expect(locator).toHaveValue(['R', 'G']);
|
||||
await expect(locator).toHaveValues(['R', 'G']);
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
|
|
@ -474,7 +474,7 @@ test.describe('should support toHaveValue with multi-select', () => {
|
|||
\`);
|
||||
const locator = page.locator('select');
|
||||
await locator.selectOption(['RR', 'GG']);
|
||||
await expect(locator).toHaveValue(['R', 'G']);
|
||||
await expect(locator).toHaveValues(['R', 'G']);
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
|
|
@ -508,7 +508,7 @@ test.describe('should support toHaveValue with multi-select', () => {
|
|||
\`);
|
||||
const locator = page.locator('select');
|
||||
await locator.selectOption(['R', 'G']);
|
||||
await expect(locator).toHaveValue([/R/, /G/]);
|
||||
await expect(locator).toHaveValues([/R/, /G/]);
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
|
|
@ -531,7 +531,7 @@ test.describe('should support toHaveValue with multi-select', () => {
|
|||
\`);
|
||||
const locator = page.locator('select');
|
||||
await locator.selectOption(['B']);
|
||||
await expect(locator).toHaveValue([/R/, /G/]);
|
||||
await expect(locator).toHaveValues([/R/, /G/]);
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
|
|
@ -564,7 +564,7 @@ test.describe('should support toHaveValue with multi-select', () => {
|
|||
\`);
|
||||
const locator = page.locator('select');
|
||||
await locator.selectOption(['B']);
|
||||
await expect(locator).toHaveValue([/R/, /G/]);
|
||||
await expect(locator).toHaveValues([/R/, /G/]);
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
|
|
@ -583,7 +583,7 @@ test.describe('should support toHaveValue with multi-select', () => {
|
|||
<input value="foo" />
|
||||
\`);
|
||||
const locator = page.locator('input');
|
||||
await expect(locator).toHaveValue([/R/, /G/]);
|
||||
await expect(locator).toHaveValues([/R/, /G/]);
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
|
|
|
|||
Loading…
Reference in a new issue