chore: move multi-select assertion to toHaveValues (#14595)

Follow-up to e0a87e52d7
This commit is contained in:
Ross Wollman 2022-06-02 16:01:34 -04:00 committed by GitHub
parent dbc2494e54
commit 978854b859
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 137 additions and 29 deletions

View file

@ -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-%%

View file

@ -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) };
}

View file

@ -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,
};

View file

@ -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(

View file

@ -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`.
*/

View file

@ -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 });