jp.co.moneyforward.autotest.actions.web.TableQuery Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of insdog-all Show documentation
Show all versions of insdog-all Show documentation
An action-based testing framework and library
The newest version!
package jp.co.moneyforward.autotest.actions.web;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import static com.github.valid8j.classic.Requires.requireNonNull;
import static com.github.valid8j.fluent.Expectations.require;
import static com.github.valid8j.fluent.Expectations.value;
import static java.util.Arrays.asList;
import static jp.co.moneyforward.autotest.framework.utils.Valid8JCliches.mapToKeyList;
///
/// A class to query HTML table object as if it were an SQL relation.
/// Note that this class is designed to select only one column.
///
///
/// ```java
/// void example() {
/// try (Playwright playwright = Playwright.create()) {
/// BrowserType chromium = playwright.chromium();
/// try (Browser browser = chromium.launch(new BrowserType.LaunchOptions().setHeadless(false))) {
/// Page page = browser.newPage();
/// page.navigate(testTableResourcePath());
/// //#js-ca-main-contents > table > thead
///
/// Locator l = TableQuery.select("事業者・年度の切替")
/// .from("body > table")
/// .where(term("事業者名", "abc-154206"))
/// .normalizeWith(normalizerFunction())
/// .build()
/// .perform(page)
/// .getFirst();
/// }
/// ```
///
///
/// **Limitation:**
///
/// - The target HTML table must have unique headers (`th`) for all columns.
/// - Only "equal" condition is supported.
/// - Only conjunctions are supported.
///
/// In case you think these need to be improved, contact the development team of *insdog*.
///
/// @param tableName A locator string to specify a table within a `Page` object.
/// @param columnName A column from which value is project to the result.
/// @param queryTerms Condition terms to select rows in a table.
/// @param normalizer A `BinaryOperator` to normalize an incomplete row.
///
/// @see TableQuery.Term
///
public record TableQuery(String tableName, String columnName, List queryTerms,
BiFunction, List, List> normalizer) {
@Override
public String toString() {
return String.format("SELECT '%s' FROM '%s' WHERE '%s'", columnName, tableName, queryTerms);
}
///
/// A method from which you can start building a query.
/// A `Builder` class object, which holds `columnName` as a column to project to the result will be returned.
///
/// @param columnName A column to be projected into the result.
/// @return A builder object.
///
public static TableQuery.Builder select(String columnName) {
Builder builder = new Builder();
builder.columnName = columnName;
return builder;
}
///
/// Performs the query on the given `page`.
///
/// @param page A page object on which this query will be performed.
/// @return A list of locators, each of whose enclosing row that satisfies the `terms`.
///
public List perform(Page page) {
String headerLocatorString = String.format("%s thead tr", this.tableName());
Locator headerRow = page.locator(headerLocatorString);
headerRow.waitFor();
Map columnIndices = composeColumnNameIndices(headerRow.locator("th"));
require(value(columnIndices).function(mapToKeyList())
.asList()
.toBe()
.containing(columnName()));
List> matches = new ArrayList<>();
Optional> lastCompleteRow = Optional.empty();
Locator rowLocator = page.locator(String.format("%s > tbody > tr", tableName()));
for (int i = 0; i < rowLocator.count(); i++) {
Locator eachRowLocator = rowLocator.nth(i);
List columnsInEachRow = toColumns(eachRowLocator);
if (isCompleteRow(columnsInEachRow, columnIndices))
lastCompleteRow = Optional.of(columnsInEachRow);
List eachRow = lastCompleteRow.filter(r -> !isCompleteRow(columnsInEachRow, columnIndices))
.map(r -> this.normalizer().apply(r, columnsInEachRow))
.orElse(columnsInEachRow);
boolean matched = true;
for (Term eachQueryTerm : queryTerms()) {
String filterTargetColumnValue = eachRow.get(columnIndices.get(eachQueryTerm.columnName()))
.textContent();
if (!filterTargetColumnValue.contains(eachQueryTerm.operand())) {
matched = false;
break;
}
}
if (matched)
matches.add(eachRow);
}
return matches.stream()
.map(c -> c.get(columnIndices.get(columnName)))
.toList();
}
private static boolean isCompleteRow(List columnsInEachRow, Map columnIndices) {
return columnsInEachRow.size() == columnIndices.size();
}
private static Map composeColumnNameIndices(Locator headerCells) {
Map columnIndices = new HashMap<>();
for (int i = 0; i < headerCells.count(); i++) {
String columnName = headerCells.nth(i).textContent();
columnIndices.put(columnName, i);
}
return columnIndices;
}
private static List toColumns(Locator row) {
return row.locator("td").all();
}
///
/// A class that represents a term in a condition to select rows.
/// When a value of the column designated by the `columnName` is equal to `operand`, the term is satisfied.
///
/// @param columnName A name of a column.
/// @param operand A value
///
public record Term(String columnName, String operand) {
public static Term term(String columnName, String operand) {
return new Term(columnName, operand);
}
}
///
/// A builder class for `TableQuery`.
///
public static class Builder {
private String tableName;
private String columnName;
private Term[] conditions;
private BinaryOperator> normalizer = (lastFullRow, incompleteRow) -> incompleteRow;
///
/// A table name on which the query will be performed.
///
/// @param tableName A locator string of the table.
/// @return This object.
///
public Builder from(String tableName) {
this.tableName = requireNonNull(tableName);
return this;
}
///
/// @param terms Conditions with which querying
/// @return This object
/// @see TableQuery.Term
///
public Builder where(Term... terms) {
this.conditions = requireNonNull(terms);
return this;
}
///
/// @param normalizer A function that normalizes incomplete row.
/// @return This object
///
public Builder normalizeWith(BinaryOperator> normalizer) {
this.normalizer = requireNonNull(normalizer);
return this;
}
///
/// Builds a `TableQuery` object from the current field values held by this object.
///
/// @return A `TableQuery` object.
///
public TableQuery build() {
return new TableQuery(this.tableName, columnName, asList(conditions), this.normalizer);
}
///
/// A shorthand method ob `build()`.
///
/// @return A built `TableQuery` object.
///
public TableQuery $() {
return build();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy